Modularité Javascript, MVC basé sur serveur et réalité commerciale

32

Je comprends que c'est une question très large, mais j'ai travaillé avec différents aspects de ce problème individuellement et j'ai du mal à rassembler tous les concepts et technologies.

Je voudrais préciser que les réponses doivent inclure ces technologies:

  • C #
  • MVC 3 avec rasoir
  • Javascript avec jQuery

Tout ce qui est au-delà de ceux-ci (tels que Backbone.js , Entity Framework , etc.) sont les bienvenus comme suggestions s'ils aident à répondre à la question qui est:

En utilisant les technologies énumérées ci-dessus, quelle est la stratégie optimale pour organiser le code et la logique tout en conservant l'évolutivité et la capacité de créer une interface utilisateur riche, rapide et propre?

Idéalement, l'accent devrait être mis sur une solution déployée dans un environnement commercial / d'entreprise. Sur cette note, la liste des technologies ci - dessus ne sera pas modifiée , veuillez donc ne pas proposer de solutions avec "vous devriez utiliser xxx au lieu de yyy que vous utilisez maintenant".

Contexte

Je travaille avec jQuery tous les jours, j'ai adopté le MVC d'ASP.NET et je travaille avec C # depuis longtemps. Vous pouvez donc présenter des solutions en supposant une connaissance intermédiaire à avancée de ces technologies.

Je vais organiser la question en parties plus petites pour rendre la réponse plus simple:

1. Structure du projet

Étant donné que je travaille avec ASP.NET MVC (dans Visual Studio 2010 ), je voudrais une solution de structure de répertoire qui offre une certaine acceptation de la disposition principale de ce type d'application. Quelque chose comme Brunch, je suppose, mais avec un peu plus de détails sur ce que chaque dossier contiendrait et comment cela fonctionne avec les autres zones de l'application.

2. Accès aux données

Je souhaite modulariser autant que possible mon accès aux données, avec une structure de type API. Vous pouvez supposer beaucoup d'objets POCO ( User, UserGroup, Customer, OrderHeader, OrderDetails, etc.), mais il y aura aussi des rapports complexes qui nécessitent des données SQL et le rendu de l' interface utilisateur attention intensive. EF + LINQ sont fantastiques pour les premiers mais pas tant pour les seconds. Je ne peux pas trouver quelque chose qui semble correspondre aux deux scénarios sans être trop compliqué ou trop simple.

3. Organisation du code côté client et rendu de l'interface utilisateur

Comme la plupart des développeurs qui ont choisi jQuery pour la première fois, je suis tombé dans le piège de mélanger le code partout où il devait aller, mais je l'ai rapidement trouvé empiler et devenir laid. Bien que j'aie fait des bonds depuis lors, j'ai toujours du mal à modulariser mon code et à travailler avec diverses parties de l'interface utilisateur sans répéter le code.

Par exemple, un morceau de code typique que je pourrais écrire ressemblerait à ceci, j'ai commenté ce qui me dérange ( notez que j'ai depuis changé pour utiliser des appels AJAX différés et séparé les demandes de données réelles de la manipulation 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();
            }
        });
    }
});

Questions générales

  • MVC client vs MVC serveur? Mon projet est déjà une structure MVC côté serveur, donc y a-t-il toujours un besoin de MVC client comme Backbone.js fournit?
  • Les fichiers Javascript doivent-ils être créés pour chaque objet (comme un OrderHeader.js) puis minifiés / fusionnés pendant la construction? Ou devrait-il y en avoir un Order.jsqui a une logique pour OrderHeader, OrderDetails, Reportsetc?
  • Comment gérer les requêtes complexes? À l'heure actuelle, ma théorie principale est /Reports/Orders-By-Date/ou quelque chose du genre et j'utilise une requête SQL personnalisée qui rend un ensemble de données personnalisé (ou ViewModel) dans la vue Razor. Mais qu'en est-il de la pagination, du tri, etc.? Est-ce mieux à faire côté client ou serveur? (supposons un ensemble de données plus grand - requête SQL de 2 à 3 secondes)
  • J'ai lu le Project Silk de Microsoft . Est-ce une bonne façon de procéder? Comment se compare-t-il à Backbone.js ou à d'autres?
  • Je suis très habitué à une architecture à N niveaux, ces concepts jettent-ils cela un peu par la fenêtre? Il semble que MVC soit comme un tas de mini-sections à N niveaux dans ce qui aurait été le niveau frontal ou supérieur dans le passé.

Encore une fois, plus vos réponses sont précises, mieux elles seront. J'ai lu beaucoup de documentation et d'exemples de haut niveau , j'essaie de mieux comprendre leur traduction en exemples réels .

Terry
la source
2
Vous avez mis beaucoup d'efforts dans cette question, mais cela ne me semble pas être une question Stackoverflow. Peut-être que les programmeurs stackexchange seraient mieux adaptés.
Pointy
3
Je ne suis pas en désaccord que c'est un sujet intéressant, mais Stackoverflow est censé être sur des questions objectives . Quelque chose comme cette question est fondamentalement l'enfant de l'affiche pour les questions qui «solliciteront probablement l'opinion, le débat, les arguments, les sondages ou les discussions prolongées».
Pointy
8
Il y a un camp de gens qui planifient la plus grande échelle tout le temps pendant que je leur retire tranquillement leurs affaires parce qu'ils ont mis trop de temps à planifier quelque chose qui ne s'est jamais produit.
Jason Sebring
1
Je suis d'accord avec @Pointy que cela appartient à la pile des programmeurs. Votre question est très intéressante et je la suivrai car je suis toujours à la recherche de conseils. Mais ce n'est pas une question objective, et cela ne finira que par des débats préférentiels. Comme toujours, faites ce qui convient le mieux à votre situation ... aucun de nous ne sait quoi que ce soit sur la structure de votre réseau, le nombre de clients ou les statistiques de trafic, ou le processus de construction ... donc la question est bien trop vague ... tout ce que je sais c'est éviter la soie. ;)
one.beat.consumer
1
Cette question correspond à la définition même de "trop ​​large" et donc "pas une vraie question". Si quoi que ce soit, les questions individuelles doivent être posées comme des questions individuelles avec un léger arrière-plan (trop et les gens vont le signaler "pas une vraie question"). Cependant, soyez prudent, un certain nombre des questions individuelles que vous posez seraient probablement signalées comme "non constructives" en elles-mêmes, donc je serais prudent sur la façon dont vous posez ces questions.
casperOne

Réponses:

10

TerryR mon ami, toi et moi devrions boire un verre. Nous avons des problèmes similaires.

1. Structure du projet: je suis d'accord avec Eduardo que la structure des dossiers dans une application MVC laisse à désirer. Vous disposez de vos dossiers Contrôleurs, Modèles et Vues standard. Mais le dossier Vues est ensuite divisé en un dossier différent pour chaque contrôleur, plus un dossier partagé. Et chaque Views / ControllerName ou Views / Shared peut être décomposé en EditorTemplates et DisplayTemplates. Mais il vous permet de décider comment organiser votre dossier Modèles (vous pouvez le faire avec ou sans sous-dossiers et déclarations d'espace de noms supplémentaires).

Dieu nous en préserve, vous utilisez des zones, qui dupliquent la structure de dossiers Contrôleurs, Modèles et Vues pour chaque zone.

/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

Cela signifie que si vous travaillez avec quelque chose comme un WidgetController, vous devez rechercher dans d'autres dossiers pour trouver les WidgetViewModels, WidgetViews, WidgetEditorTemplates, WidgetDisplayTemplates, etc. ces conventions MVC. Pour ce qui est de mettre un modèle, un contrôleur et une vue dans le même dossier mais avec des espaces de noms différents, j'évite cela car j'utilise ReSharper. Il soulignera un espace de noms qui ne correspond pas au dossier où se trouve la classe. Je sais que je pourrais désactiver cette fonction R #, mais cela aide dans d'autres parties du projet.

Pour les fichiers non-classe, MVC vous donne du contenu et des scripts prêts à l'emploi. Nous essayons de garder tous nos fichiers statiques / non compilés à ces endroits, encore une fois, pour suivre la convention. Chaque fois que nous incorporons une bibliothèque js qui utilise des thèmes (images et ou css), les fichiers de thème vont tous quelque part sous / content. Pour le script, nous les mettons tous directement dans / scripts. À l'origine, c'était pour obtenir JS intellisense de VS, mais maintenant que nous obtenons JS intellisense de R # quel que soit le placement dans / scripts, je suppose que nous pourrions nous en écarter et diviser les scripts par dossier pour mieux organiser. Utilisez-vous ReSharper? C'est de l'or pur IMO.

Un autre petit morceau d'or qui aide beaucoup à la refactorisation est le T4MVC. En utilisant cela, nous n'avons pas besoin de taper des chemins de chaîne pour les noms de zone, les noms de contrôleur, les noms d'action, même les fichiers dans le contenu et les scripts. T4MVC tape fortement toutes les cordes magiques pour vous. Voici un petit exemple de la façon dont la structure de votre projet n'a pas autant d'importance si vous utilisez 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. Accès aux données: je n'ai aucune expérience avec PetaPoco, mais je suis sûr que cela vaut la peine de vérifier. Pour vos rapports complexes, avez-vous envisagé les services de création de rapports SQL Server? Ou exécutez-vous sur une autre base de données? Désolé, je ne sais pas exactement ce que vous demandez. Nous utilisons EF + LINQ, mais nous mettons également certaines connaissances sur la façon de générer des rapports dans les classes de domaine. Ainsi, nous avons un référentiel d'appels de service de domaine d'appel de contrôleur, au lieu d'avoir un référentiel d'appels de contrôleur directement. Pour les rapports ad hoc, nous utilisons SQL Reporting Services, ce qui n'est pas parfait, mais nos utilisateurs aiment pouvoir importer facilement des données dans Excel, et SSRS nous facilite la tâche.

3. Organisation du code côté client et rendu de l'interface utilisateur: c'est là que je pense que je peux être en mesure d'offrir de l'aide. Prenez une page du livre de validation MVC discrète et AJAX discrète. Considère ceci:

<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" />

Ignorez la fonction de succès ajax pour l'instant (plus d'informations à ce sujet plus tard). Vous pouvez vous en tirer avec un seul script pour certaines de vos actions:

$('.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();
                    }
                }
            }
        });
    }
});

Le code ci-dessus prendra soin de la confirmation, en montrant le spinner, en affichant le message d'attente et en masquant le message spinner / wait une fois l'appel ajax terminé. Vous configurez les comportements à l'aide d'attributs data- *, comme les bibliothèques discrètes.

Questions générales

- MVC client vs MVC serveur? Je n'ai pas essayé de librarifier les actions que vous avez effectuées dans la fonction de réussite, car il semble que votre contrôleur retourne JSON. Si vos contrôleurs retournent JSON, vous voudrez peut-être regarder KnockoutJS. Knockout JS version 2.0 est sortie aujourd'hui . Il peut se connecter directement à votre JSON, de sorte qu'un clic observable peut automatiquement lier des données à vos modèles javascript. D'un autre côté, si cela ne vous dérange pas que vos méthodes d'action ajax retournent du HTML au lieu de JSON, elles peuvent renvoyer l'UL déjà construite avec ses enfants LI, et vous pouvez l'ajouter à un élément en utilisant data-myapp-response = "résultats". Votre fonction de réussite ressemblerait alors à ceci:

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

Pour résumer ma meilleure réponse à cela, si vous devez renvoyer JSON à partir de vos méthodes d'action, vous sautez la vue côté serveur, donc ce n'est vraiment pas le MVC du serveur - c'est juste MC. Si vous renvoyez PartialViewResult avec html aux appels ajax, il s'agit du serveur MVC. Donc, si votre application doit renvoyer des données JSON pour les appels ajax, utilisez MVVM client comme KnockoutJS.

Quoi qu'il en soit, je n'aime pas le JS que vous avez publié car il mélange votre mise en page (balises html) avec un comportement (chargement de données asynchrones). Choisir MVC serveur avec des vues html partielles ou MVVM client avec des données de modèle de vue JSON pur résoudra ce problème pour vous, mais la construction manuelle de DOM / HTML en javascript viole la séparation des préoccupations.

- Création de fichiers Javascript Apparemment, des fonctionnalités de minification arrivent dans .NET 4.5 . Si vous optez pour la voie discrète, rien ne devrait vous empêcher de charger tous vos fichiers de script JS en 1. Je serais prudent sur la création de différents fichiers JS pour chaque type d'entité, vous vous retrouverez avec une explosion de fichiers JS. N'oubliez pas qu'une fois votre fichier de script chargé, le navigateur doit le mettre en cache pour les demandes futures.

- Requêtes complexes Je ne considère pas que des fonctionnalités telles que la pagination, le tri, etc. soient complexes. Ma préférence est de gérer cela avec les URL et la logique côté serveur, pour rendre les requêtes db aussi limitées que nécessaire. Cependant, nous sommes déployés sur Azure, donc l'optimisation des requêtes est importante pour nous. Par exemple: /widgets/show-{pageSize}-per-page/page-{pageNumber}/sort-by-{sortColumn}-{sortDirection}/{keyword}. EF et LINQ to Entities peuvent gérer la pagination et le tri avec des méthodes telles que .Take (), .Skip (), .OrderBy () et .OrderByDescending (), afin que vous obteniez ce dont vous avez besoin pendant le trajet db. Je n'ai pas encore trouvé le besoin d'une bibliothèque cliente, donc honnêtement, je ne sais pas grand-chose à leur sujet. Consultez d'autres réponses pour plus de conseils à ce sujet.

- Projet soie Jamais entendu parler de celui-ci, devra le vérifier. Je suis un grand fan de Steve Sanderson, de ses livres, de son BeginCollectionItem HtmlHelper et de son blog. Cela dit, je n'ai aucune expérience avec KnockoutJS en production . J'ai vérifié ses tutoriels, mais j'essaie de ne pas m'engager sur quelque chose jusqu'à ce que ce soit au moins la version 2.0. Comme je l'ai mentionné, KnockoutJS 2.0 vient de sortir.

- N-tier Si par niveau vous voulez dire une machine physique différente, alors non, je ne pense pas que quelque chose sort par les fenêtres. En général, 3 niveaux signifie que vous avez 3 machines. Vous pouvez donc avoir un gros client comme niveau de présentation, qui s'exécute sur la machine d'un utilisateur. Le gros client peut accéder à un niveau de service, qui s'exécute sur un serveur d'applications et renvoie XML ou autre au gros client. Et le niveau de service peut obtenir ses données d'un serveur SQL sur une 3e machine.

MVC est une couche, sur 1 niveau. Vos contrôleurs, modèles et vues font tous partie de votre couche de présentation, qui est à 1 niveau dans l'architecture physique. MVC implémente le modèle Model-View-Controller, qui est l'endroit où vous pouvez voir des couches supplémentaires. Cependant, essayez de ne pas considérer ces 3 aspects comme des niveaux ou des couches. Essayez de les considérer tous comme des problèmes de présentation.

Mise à jour après le commentaire de pres / bus / data

D'accord, vous utilisez donc les niveaux et les couches de manière interchangeable. J'utilise généralement le terme «couche» pour les divisions logiques / projets / assemblages et le niveau pour la séparation physique du réseau. Désolé pour la confusion.

Vous trouverez un certain nombre de personnes dans le camp MVC qui disent que vous ne devez pas utiliser les «modèles» dans MVC pour votre modèle de données d'entité, ni utiliser vos contrôleurs pour la logique métier. Idéalement, vos modèles doivent être des ViewModels spécifiques à la vue. En utilisant quelque chose comme Automapper, vous prenez vos entités de votre modèle de domaine et les DTO dans ViewModels, sculptées spécifiquement pour être utilisées par la vue.

Toutes les règles métier doivent également faire partie de votre domaine, et vous pouvez les implémenter à l'aide des services de domaine / modèle d'usine / tout ce qui est approprié dans votre couche de domaine, pas dans la couche de présentation MVC. Les contrôleurs doivent être stupides, mais pas tout à fait aussi stupides que les modèles, et doivent donner la responsabilité au domaine pour tout ce qui nécessite des connaissances commerciales. Les contrôleurs gèrent le flux des demandes et des réponses HTTP, mais tout ce qui a une réelle valeur commerciale doit être supérieur au niveau de rémunération du contrôleur.

Ainsi, vous pouvez toujours avoir une architecture en couches, avec MVC comme couche de présentation. Il s'agit d'un client de votre couche d'application, couche de service ou couche de domaine, selon la façon dont vous l'architecturez. Mais en fin de compte, votre modèle d'entité doit faire partie du domaine, pas les modèles dans MVC.

danludwig
la source
Je suis totalement d'accord avec cette réponse! Surtout: • Resharper est un génie MVC ... de la vérification des erreurs à la navigation IDE, son utilité me bluffe! • MVC côté serveur est presque toujours la meilleure approche • MVC n'est pas 3 niveaux séparés, c'est une seule couche de présentation - je n'y ai jamais vraiment pensé de cette façon, mais c'est absolument correct.
Scott Rippey
Très belle réponse, certainement ce que je cherchais au prix de mon 300 rep. Les boissons sont sur moi si vous êtes dans la région de Toronto :)
btw J'ai toujours considéré N-tier comme Pres / Bus / Data, peu importe où ils étaient physiquement assis. C'est pourquoi j'ai dit que MVC supprime presque cette architecture car elle combine essentiellement les 3, ce que vous avez dit est quelque peu d'accord avec cela, mais donne également une perspective différente à ce sujet.
Je mettrais en garde contre l'approche ViewModel, modèle par vue. J'ai récemment rencontré une situation où je souhaitais plus tard que je n'avais pas cette abstraction de DTO à ViewModel. Voir: stackoverflow.com/q/7181980/109456
En règle générale, je n'aime pas voir le jQuery et plutôt écrire des objets avec des interfaces que tout développeur côté serveur serait capable de comprendre assez rapidement avec JQ ou l'API DOM faisant l'affaire à l'intérieur. J'aime aussi beaucoup le concept URLConfig de Django et je l'ai trouvé utile pour configurer des objets à implémenter sur des pages. Je n'ai aucune idée de ce que le MV? les bibliothèques sont censées faire pour moi cependant. Ils ne conviennent pas parfaitement au problème, l'OMI et la délégation d'événement DOM + est tout le modèle dont j'ai besoin pour gérer les pages sans être excessivement lié à une structure spécifique.
Erik Reppen
6

Je ne vais pas écrire une réponse complète, mais je veux partager quelques conseils.

Mes conseils:

1. Structure du projet
J'ai trouvé que la structure MVC par défaut n'était pas bonne pour moi. Je travaille généralement dans le contrôleur, les vues et le modèle de la même entité (pensez produit, commande, client) en même temps. Donc, j'aime avoir les fichiers dans le même dossier, mais avec des espaces de noms différents.

2. Données
Si vous optez pour Linq-to-SQL ou EF, vous le regretterez plus tard.
J'utilise PetaPoco qui me permet d'exécuter la récupération et la mise à jour des enregistrements SQL sans la douleur de mappage, mais sans apprendre une nouvelle façon de faire les choses et sans les cauchemars de performance.

J'ai un générateur de code pour créer la classe POCO initiale avec les attributs PetaPoco, puis je change la classe lorsqu'un champ est ajouté ou supprimé.

PetaPoco fonctionne avec des classes dynamiques et standard, donc vous n'avez aucun compromis (Massive est toute dynamique et Dapper toutes les classes standard)

Je génère également un SQL maître , en utilisant le SqlBuilder intégré, qui contient toutes les jointures standard pour l'entité, mais pas de WHERE, donc je réutilise le même SQL pour récupérer une entité ou une liste.

3. Jquery Vous pouvez standardiser certaines parties de l'interface utilisateur à l'aide d'un appel jQuery général (bourrant certaines données à l'intérieur de l'élément HTML).

Par exemple, j'ai ceci à supprimer.

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");
        }
    }
});

J'ai juste besoin d'ajouter la classe jbtn-borrarà un lien hypertexte, et il affiche une boîte de dialogue, supprimer l'enregistrement et masquer letr

Mais n'y pensez pas trop. Votre application brillera avec les petites touches dans chaque vue.

Client MVC vs serveur MVC
Server MVC. Profitez des vues partielles que vous pouvez utiliser dans le rendu initial et actualisez certaines parties avec Ajax en utilisant la même vue. Voir cet excellent article

Comment les requêtes complexes doivent-elles être traitées (appelons-le un rapport)
J'utilise une classe qui a les paramètres de rapport comme propriétés (pratique pour utiliser le mappage automatique MVC) et une Generateméthode qui exécute la requête et remplit une liste d'une classe personnalisée (si vous ne 't have a class that fit the ViewModel)
Vous pouvez utiliser cette classe comme modèle de la vue et remplir le tableau avec la liste générée.

Project Silk
Overarchitected de Microsoft . Courez aussi vite que possible dans la direction opposée.

Eduardo Molteni
la source
C'est drôle, en lisant Project Silk, je ressentais toujours ce sentiment tenace et je ne pouvais pas le placer. Overarchitected aurait pu être que ...
3

1. Structure du projet

J'ai 2 fichiers de projet dans ma solution

1) Couche Service / Business Je place toute ma logique métier et mon code d'accès DB et POCO dans ce projet séparé. Pas besoin d'une couche d'accès aux données si vous utilisez un ORM comme ORM abstrait déjà la couche DB.

2) La couche d'interface utilisateur contient toutes mes vues, contrôleurs, modèles, scripts, CSS

J'essaie de faire en sorte que mes contrôleurs, vues, scripts et CSS utilisent tous une structure de dossiers similaire. Structurez également mes fichiers pour qu'ils correspondent le plus possible au chemin URL. Pour éviter d'avoir à écrire un routage personnalisé.

Utilisez autant que possible les modèles d'affichage, les modèles d'édition, les vues partielles et le dossier partagé.

Je structure ensuite tous mes scripts pour qu'ils correspondent aux mêmes zones, contrôleurs de mes fichiers c #. J'aurais donc un fichier common.js à la racine, un fichier js par page et un fichier common.js pour chaque zone.

Fichiers CSS J'ai normalement 2 + n (où n est le nombre de zones) Le premier fichier CSS est CSS uniquement pour la page de destination uniquement pour aider à un temps de chargement de page plus rapide (probablement pas si important pour l'environnement professionnel / d'entreprise) 2e fichier CSS est un fichier common.css qui a tous les styles pour toutes les autres pages. Ensuite, un autre fichier common.css pour chaque zone, par exemple un fichier AdminArea.css qui a CSS pour chaque page d'administration.

2. Accès aux données

Si j'utilise Entity Framework, j'utilise CodeFirst car il fonctionne très bien avec POCOS et vous n'avez pas de modèle à maintenir. nHibernate est beaucoup plus puissant mais a une courbe d'apprentissage pas à pas. Pour la pagination des résultats de base de données, j'ai une classe util c # réutilisable et une vue patiale que j'utilise pour toutes mes vues.

Pour les requêtes complexes et la génération de rapports, j'utilise des procédures stockées. Ils sont beaucoup plus faciles à écrire et à maintenir et offrent plus de puissance au LINQ. Ils peuvent également être réutilisés par d'autres services comme SSRS. J'utilise automapper pour convertir le jeu de données retourné dans le même cadre que POCO.

3. Organisation du code côté client et rendu de l'interface utilisateur

La réponse d'Eduardo Molteni a un bon exemple de code. De plus, je recommanderais certainement d'utiliser knockoutjs car il a à la fois de bons modèles et des liaisons. Si vous utilisez JSON pour tous vos appels AJAX que j'utilise beaucoup, avoir la correspondance automatique de l'interface utilisateur avec les objets JS est un énorme gain de temps.

Questions générales

Les requêtes complexes doivent vivre dans un proc stocké. (voir le commentaire emeraldcode.com)

Vous conservez toujours votre architecture à plusieurs niveaux en utilisant ce MVC.

Daveo
la source
1

J'ai récemment été ému de croire que, si vous envisagez d'utiliser les trois technologies que vous avez répertoriées, vous devez d'abord commencer par supposer l'adoption d' Orchard CMS . Je pense que c'est la meilleure réponse unique à votre exigence centrale:

Quelle est la stratégie optimale pour organiser le code et la logique tout en conservant l'évolutivité et la possibilité de créer une interface utilisateur riche, rapide et propre?

Dans le scénario Ochard, tout ce que vous ne pouvez pas résoudre via ses mécanismes de configuration, vous le feriez alors soit par l'ajout de modules en ligne gratuits, soit par l'écriture de votre propre module (qui sont bien sûr C #, rasoir, etc.). L'organisation du code est une force d'Orchard.

En ce qui concerne l'accès aux données, il y a suffisamment d'avantages et d'inconvénients à un ORM à part entière que j'ai également pensé qu'un micro-ORM est la meilleure prise. Essayez Massive ou Dapper . Les deux ont été présentés sur Hanselminutes . Je vais résumer les deux en disant ceci: les abstractions de SQL se décomposent presque toujours à mesure qu'un projet s'intensifie. En fin de compte, la meilleure solution pour l'accès à la base de données est cette abstraction appelée SQL (peu de sarcasme, mais vrai). Laissez le micro-ORM fonctionner avec cela, et vous avez de l'or.

Associez Orchard aux micro-ORM et vous pouvez couper l'acier comme du beurre. Euh, ce qui signifie que vous pouvez développer rapidement, évoluer et avoir du code facilement maintenable par une équipe qui reçoit le transfert.

Brent Arias
la source
0

Je ne sais pas comment j'ai raté cette question, mais j'ajouterai mes deux cents deux ans plus tard.

MVC client vs MVC serveur? Mon projet est déjà une structure MVC côté serveur, donc y a-t-il toujours un besoin de MVC client comme Backbone.js fournit?

MVC et MV? avant même qu'il ne soit poussé vers le côté client, il est essentiellement devenu un terme marketing qui promet vraiment que les données seront séparées d'une manière ou d'une autre, ce qui est dans l'ensemble une excellente idée mais pas vraiment difficile à bricoler. Quelle que soit l'approche que vous adoptez, juste avant ou juste au milieu des modifications du HTML qui affectent les possibilités de présentation ou d'interaction, c'est l'endroit le plus horrible pour trier ce que l'entreprise veut que vous fassiez avec les données.

Il n'y a rien de spécial dans la «logique de la vue». Le même principe devrait s'appliquer à toute logique. Et c'est-à-dire, ne faites rien maintenant qui aurait été beaucoup plus logique à faire avant maintenant. Lorsque tous vos canards sont alignés avant de transmettre des données ou de lancer un nouveau processus, cette phase précédente est susceptible d'être beaucoup plus réutilisable pour tout autre élément du système faisant quelque chose de similaire.

Les fichiers Javascript doivent-ils être créés pour chaque objet (comme un OrderHeader.js) puis minifiés / fusionnés pendant la construction? Ou devrait-il y avoir juste un Order.js qui a une logique pour OrderHeader, OrderDetails, Reports, etc.?

Cela dépend vraiment de vous, mais j'essaierais de m'éloigner de la chose à fichier unique et à classe unique. Je n'ai jamais compris pourquoi il était utile par exemple de devoir trouver le fichier abstrait et l'interface, et les fichiers implémentant, etc ... Catégoriser sur des préoccupations plus larges. ctrl + f n'est pas si difficile à utiliser si ça dure un peu.

Cela dit, vous ne devez jamais recombiner JS pour réduire la taille des fichiers sur le Web. Les navigateurs mettent en cache JS, vous ne faites donc que forcer le rechargement du même JavaScript en collant l'ancien JS dans de nouveaux fichiers. À l'exception de quantités énormes de JavaScript, la seule fois où vous ne devriez pas avoir tout le JS sur la page est quand une très grande quantité de celui-ci qui est très spécifique à une section du site sans chevauchement / zones grises ne sera jamais nécessaire sur une donnée page.

Et FFS ne s'embarrasse pas de la gestion des dépendances avec JavaScript sur le web. Require.js sur les sites de complexité moyenne à faible me donne envie de clubter des bébés phoques. Collez vos bibliothèques tierces dans un bloc supérieur. Vos bibliothèques internes dans le deuxième bloc. Et puis votre code d'implémentation (qui ne devrait jamais être un dixième aussi long que votre code de bibliothèque interne - c'est-à-dire très succinct et clair et facile à comprendre) dans ce troisième bloc.

Comment gérer les requêtes complexes? À l'heure actuelle, ma théorie principale est / Reports / Orders-By-Date / ou quelque chose du genre et j'utilise une requête SQL personnalisée qui rend un ensemble de données personnalisé (ou ViewModel) dans la vue Razor. Mais qu'en est-il de la pagination, du tri, etc.? Est-ce mieux à faire côté client ou serveur? (supposons un ensemble de données plus grand - requête SQL de 2 à 3 secondes) J'ai lu le Project Silk de Microsoft. Est-ce une bonne façon de procéder? Comment se compare-t-il à Backbone.js ou à d'autres?

Honnêtement, je dirais tout ce qui est plus facile pour vous et qui ne pue pas le client. Les pages Web se chargent assez rapidement sur la technologie moderne. Si la mise en œuvre dans Ajax est très pénible pour vous, ne le faites pas. Allez simplement avec ce que vous connaissez le mieux, puis vous pourrez vous imaginer plus tard et voir comment vous l'aimez pour la pagination. Si vous créez une nouvelle application complexe à partir de zéro, commencez par essentiel et appuyez sur neat-o plus tard.

Je suis très habitué à une architecture à N niveaux, ces concepts jettent-ils cela un peu par la fenêtre? Il semble que MVC soit comme un tas de mini-sections à N niveaux dans ce qui aurait été le niveau frontal ou supérieur dans le passé.

Cela dépend vraiment de la fantaisie de quiconque de quel MV? est. OMI, le microcosme a tendance à très bien fonctionner. Une classe de widget qui sépare les données, la communication et les éléments liés à la vue fonctionne très bien en interne. Sur le Web côté client, l'important, l'OMI, est de maintenir un équilibre entre les préoccupations séparées sans se fragmenter inutilement en de minuscules préoccupations dont le réassemblage rend difficile la compréhension, la réutilisation et la modification des choses. La POO "duh" de base fonctionne très bien ici. Vous ne voulez pas de processus complexes. Vous voulez évidemment des choses nommées qui peuvent être déplacées et dites de faire des choses. Voici quelques conseils à ce sujet:

  • BAISER cette interface (OOP), je ne veux pas voir DOM ou jQuery ou toute autre chose qu'un développeur côté serveur ne pourrait pas comprendre assez rapidement dans mon code d'implémentation. Tout ce que cette personne devrait savoir, c'est quelle classe gifler sur un conteneur div et quel commutateur basculer pour rendre un ensemble assez générique d'interface utilisateur actif sur une page donnée. Les variations sur un thème doivent encore être accomplies en passant des objets d'options bien documentés / commentés avant de commencer à regarder document.get <anything> ou à comprendre quoi que ce soit au-delà des bases les plus élémentaires du CSS.

  • D'accord, alors comment faites-vous cela? Eh bien, nous avons déjà un modèle. Cela s'appelle le DOM. Et nous avons une délégation d'événement. Si vous ne désactivez pas sans discernement le bouillonnement des événements (ne le faites pas - il est là parce que c'est utile), vous pouvez ramasser chaque élément même du corps si vous le souhaitez. Examinez ensuite la propriété cible de l'objet d'événement passé et déterminez qui vient de «faire quoi que ce soit». Si vous structurez un document HTML de manière sensée, il n'y a aucune raison de ne pas l'utiliser comme modèle de délégation. Le comportement et la structure du contenu sont naturellement liés. Il est normal que les deux aient des identifiants qui se chevauchent.

  • Ne payez pas pour la liaison de données Et par "payer", j'entends bien sûr "gifler une bibliothèque sur votre base de code qui insiste pour que vous fassiez les choses juste-donc tout le temps afin d'obtenir un avantage miracle qui n'est en fait pas difficile à bricoler." Le système d'événements de JQ le rend assez facile.

Exemple de temps:

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!
  • Ne cachez pas le Web La principale source de succion dans toutes les premières tentatives pour rendre le côté client facile pour le côté serveur et les développeurs d'applications articulés sur ce point critique. Les requêtes HTTP ne sont pas et n'ont jamais été compliquées. Ils ne nécessitaient pas une couche 18! @ # $ Ing confondant nom d'événement-nom-à-chaque-étape afin de le rendre plus facile à comprendre. De même, il y a beaucoup à savoir sur le côté client, mais il n'y a aucune raison de se cacher du HTML et du DOM qui interagit avec lui en frappant un grand modèle géant dessus. C'est déjà un gros modèle géant et ça marche très bien. Tout ce dont nous avons besoin pour le rendre un peu plus gérable, ce sont des pratiques de POO sensées et des connaissances JS et DOM.

  • Favoriser la flexibilité

EXTjs <==== échelle de flexibilité ====> jQuery (pas nécessairement aucun de ses plug-ins)

IMO, les outils qui vous permettent de bricoler rapidement sont toujours le meilleur choix. Les outils qui ont tout fait pour vous ne sont le bon choix que si personne au-dessus de votre tête n'est particulièrement pointilleux sur les détails et que cela ne vous dérange pas de céder le contrôle à la chose même qui est censée vous aider. J'ai en fait vu des plug-ins qui valident le HTML pour s'assurer que vous ne faufilez pas un autre type d'élément avec tous les mêmes traits d'affichage exacts. Pourquoi? Je n'ai que des théories. Je pense que cela se résume à des finalistes détestant vraiment l'idée que quelqu'un utilise ses trucs d'une manière qui n'était pas prévue et c'est toujours inévitablement ce que quelqu'un veut que vous fassiez dans l'interface utilisateur.

Erik Reppen
la source