Modularidad de Javascript, MVC basado en servidor y realidad empresarial

32

Entiendo que esta es una pregunta muy amplia, pero he trabajado con varios aspectos de este problema individualmente y estoy luchando por unir todos los conceptos y tecnologías.

Me gustaría especificar que las respuestas deben incluir estas tecnologías:

  • DO#
  • MVC 3 con maquinilla de afeitar
  • Javascript con jQuery

Cualquier cosa por encima y más allá de eso (como Backbone.js , Entity Framework , etc.) son bienvenidas como sugerencias si ayudan a responder la pregunta que es:

Usando las tecnologías mencionadas anteriormente, ¿cuál es una estrategia óptima para organizar el código y la lógica mientras se mantiene la escalabilidad y la capacidad de crear una interfaz de usuario rica, rápida y limpia?

Idealmente, el enfoque debe centrarse en una solución que se implementa en un entorno empresarial / corporativo. En esa nota, la lista de tecnologías anterior no se cambiará, así que no ofrezca soluciones con "debería usar xxx en lugar de yyy que está usando ahora".

Fondo

Trabajo con jQuery todos los días, he adoptado el MVC de ASP.NET y he estado trabajando con C # durante mucho tiempo. Por lo tanto, puede presentar soluciones asumiendo un conocimiento intermedio a avanzado de esas tecnologías.

Organizaré la pregunta en partes más pequeñas para que sea más fácil responder a:

1. Estructura del proyecto

Dado que estoy trabajando con ASP.NET MVC (en Visual Studio 2010 ), me gustaría una solución de estructura de directorio que ofrezca cierta aceptación del diseño principal de este tipo de aplicación. Algo como Brunch , supongo, pero con un poco más de detalle de lo que contendría cada carpeta y cómo funciona con otras áreas de la aplicación.

2. Acceso a datos

Me gustaría modularizar mi acceso a datos tanto como pueda, con una estructura de tipo API. Se puede suponer una gran cantidad de objetos POCO ( User, UserGroup, Customer, OrderHeader, OrderDetails, etc), pero también habrá algunos informes complejos que requieren datos SQL intensiva y representación de IU cuidado. EF + LINQ son fantásticos para el primero pero no tanto para el segundo. No puedo encontrar algo que parezca encajar en ambos escenarios sin ser demasiado complicado o demasiado simple.

3. Organización del código del lado del cliente y representación de la interfaz de usuario

Como la mayoría de los desarrolladores que recogieron jQuery por primera vez, caí en la trampa de mezclar el código donde fuera necesario, pero rápidamente lo encontré acumulándose y volviéndose feo. Aunque he avanzado a pasos agigantados desde entonces, todavía me cuesta modularizar mi código y trabajar con varias partes de la interfaz de usuario sin repetir el código.

Como ejemplo, una pieza típica de código que podría escribir se vería así, he comentado las cosas que me molestan ( tenga en cuenta que desde entonces cambié a usar llamadas AJAX diferidas y separé las solicitudes de datos reales de la manipulación 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();
            }
        });
    }
});

Preguntas generales

  • Cliente MVC vs. servidor MVC? Mi proyecto ya es una estructura MVC del lado del servidor, por lo que todavía hay una necesidad de MVC del cliente como Backbone.js.
  • ¿Deben crearse archivos Javascript para cada objeto (como un OrderHeader.js) y luego minimizarse / fusionarse durante la construcción? ¿O debería haber una Order.jsque tenga lógica para OrderHeader, OrderDetails, Reportsetc.?
  • ¿Cómo deben manejarse las consultas complejas? En este momento, mi teoría principal es /Reports/Orders-By-Date/o algo por el estilo y uso una consulta SQL personalizada que representa un conjunto de datos personalizado (o ViewModel) en la Vista Razor. Pero, ¿qué pasa con la paginación, la clasificación, etc.? ¿Es mejor hacerlo por parte del cliente o del servidor? (suponga un conjunto de datos más grande: consulta SQL de 2 a 3 segundos)
  • He leído el Proyecto Silk de Microsoft . ¿Es este un buen camino a seguir? ¿Cómo se compara con Backbone.js u otros?
  • Estoy muy acostumbrado a una arquitectura de N niveles, ¿estos conceptos arrojan algo por la ventana? Parece que MVC es como un grupo de mini secciones en N niveles dentro de lo que hubiera sido el front-end o el nivel superior en el pasado.

Una vez más, cuanto más específicas sean sus respuestas, mejores serán. He leído una gran cantidad de documentación y ejemplos de alto nivel , estoy tratando de entender mejor traducirlo a ejemplos del mundo real .

Terry
fuente
2
Pones mucho esfuerzo en esta pregunta, pero simplemente no me parece una pregunta de Stackoverflow. Quizás los programadores stackexchange encajarían mejor.
Puntiagudo
3
No estoy de acuerdo con que es un tema interesante, pero se supone que Stackoverflow se trata de preguntas objetivas . Algo así como esta pregunta es básicamente el tema principal de las preguntas que "probablemente solicitarán opinión, debate, argumentos, encuestas o debates extensos".
Puntiagudo
8
Hay un grupo de personas que planean la mayor escala todo el tiempo, mientras que yo les quito sus negocios en silencio porque se demoraron demasiado en planificar algo que nunca sucedió.
Jason Sebring
1
Estoy de acuerdo con @Pointy en que esto pertenece a la pila de programadores. Su pregunta es muy interesante y la seguiré porque siempre estoy buscando consejos. Pero no es una pregunta objetiva, y solo terminará en debates preferenciales. Como siempre, haga lo que funcione mejor para su situación ... ninguno de nosotros sabe nada sobre la estructura de su red, el número de clientes o las estadísticas de tráfico, o el proceso de compilación ... así que la pregunta es MUY vaga ... todo lo que sé es Evita la seda. ;)
one.beat.consumer
1
Esta pregunta se ajusta a la definición misma de "demasiado amplia" y por lo tanto "no es una pregunta real". En todo caso, las preguntas individuales deben hacerse como preguntas individuales con un poco de trasfondo (demasiado y la gente lo marcará como "no es una pregunta real"). Sin embargo, tenga cuidado, varias de las preguntas individuales que está haciendo probablemente se marcarán como "no constructivas" por sí mismas, por lo que tendré cuidado con la forma en que hace esas preguntas.
casperOne

Respuestas:

10

Terry, mi amigo, tú y yo deberíamos tomar una copa. Tenemos algunos problemas similares.

1. Estructura del proyecto: estoy de acuerdo con Eduardo en que la estructura de carpetas en una aplicación MVC deja algo que desear. Tiene sus carpetas estándar de Controladores, Modelos y Vistas. Pero luego la carpeta Vistas se divide en una carpeta diferente para cada Controlador, más una carpeta Compartida. Y cada Vistas / Nombre del controlador o Vistas / Compartidas se pueden desglosar en Plantillas de editor y Plantillas de pantalla. Pero le permite decidir cómo organizar su carpeta Modelos (puede hacerlo con o sin subcarpetas y declaraciones de espacio de nombres adicionales).

Dios no permita que esté utilizando Áreas, que duplican la estructura de carpetas de Controladores, Modelos y Vistas para cada área.

/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

Esto significa que si está trabajando con algo como un WidgetController, tiene que buscar en otras carpetas para encontrar los WidgetViewModels, WidgetViews, WidgetEditorTemplates, WidgetDisplayTemplates relacionados, etc. Estas convenciones MVC. En cuanto a poner un modelo, controlador y vista en la misma carpeta pero con diferentes espacios de nombres, evito esto porque uso ReSharper. Subrayará un espacio de nombres que no coincide con la carpeta donde se encuentra la clase. Sé que podría desactivar esta función R #, pero ayuda en otras partes del proyecto.

Para archivos que no son de clase, MVC le ofrece contenido y secuencias de comandos de fábrica. Intentamos mantener todos nuestros archivos estáticos / no compilados en estos lugares, nuevamente, para seguir la convención. Cada vez que incorporamos una biblioteca js que usa temas (imágenes y / o CSS), todos los archivos de temas van a algún lugar debajo de / content. Para el script, simplemente los colocamos directamente en / scripts. Originalmente, esto era para obtener JS intellisense de VS, pero ahora que obtenemos JS intellisense de R # independientemente de la ubicación en / scripts, supongo que podríamos desviarnos de eso y dividir los scripts por carpeta para organizar mejor. ¿Estás usando ReSharper? Es oro puro OMI.

Otra pequeña pieza de oro que ayuda mucho con la refactorización es T4MVC. Con esto, no necesitamos escribir rutas de cadena para nombres de área, nombres de controlador, nombres de acción, incluso archivos en contenido y scripts. T4MVC teclea todas las cadenas mágicas por ti. Aquí hay una pequeña muestra de cómo la estructura de su proyecto no importa tanto si está 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. Acceso a datos: no tengo experiencia con PetaPoco, pero estoy seguro de que vale la pena echarle un vistazo. Para sus informes complejos, ¿ha considerado los servicios de informes de SQL Server? O, ¿estás corriendo en un db diferente? Lo siento, no tengo claro qué es exactamente lo que estás pidiendo. Usamos EF + LINQ, pero también ponemos cierto conocimiento sobre cómo generar informes en las clases de dominio. Por lo tanto, tenemos un repositorio de llamadas de servicio de dominio de llamada de controlador, en lugar de tener un repositorio de llamadas de controlador directamente. Para los informes ad-hoc utilizamos SQL Reporting Services, que de nuevo no es perfecto, pero a nuestros usuarios les gusta poder incorporar datos a Excel fácilmente, y SSRS nos lo pone fácil.

3. Organización del código del lado del cliente y representación de la interfaz de usuario: aquí es donde creo que puedo ofrecerle ayuda. Tome una página del libro de MVC discreta validación y discreta AJAX. Considera esto:

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

Ignore la función de éxito de ajax por ahora (más sobre esto más adelante). Puede salirse con la suya con un solo script para algunas de sus acciones:

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

El código anterior se encargará de la confirmación, mostrando la ruleta, mostrando el mensaje de espera y ocultando la ruleta / mensaje de espera después de que se complete la llamada ajax. Configura los comportamientos utilizando atributos data- *, como las bibliotecas discretas.

Preguntas generales

- Cliente MVC vs. servidor MVC? No traté de bibrarificar las acciones que realizó en la función de éxito porque parece que su controlador está devolviendo JSON. Si sus controladores están devolviendo JSON, es posible que desee ver KnockoutJS. La versión 2.0 de Knockout JS fue lanzada hoy . Se puede conectar directamente a su JSON, por lo que un clic observable puede vincular automáticamente los datos a sus plantillas de JavaScript. Por otro lado, si no le importa que sus métodos de acción ajax devuelvan HTML en lugar de JSON, pueden devolver el UL ya construido con sus elementos secundarios LI, y puede agregarlo a un elemento utilizando data-myapp-response = "resultados". Su función de éxito se vería así:

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

Para resumir mi mejor respuesta para esto, si debe devolver JSON de sus métodos de acción, está omitiendo la Vista del lado del servidor, por lo que esto realmente no es MVC del servidor, es solo MC. Si devuelve PartialViewResult con html a llamadas ajax, este es el servidor MVC. Entonces, si su aplicación debe devolver datos JSON para llamadas ajax, use MVVM del cliente como KnockoutJS.

De cualquier manera, no me gusta el JS que publicaste porque combina tu diseño (etiquetas html) con el comportamiento (carga de datos asincrónica). Elegir MVC de servidor con vistas html parciales o MVVM de cliente con datos de modelos de vista JSON puros resolverá este problema, pero construir manualmente DOM / HTML en JavaScript viola la separación de preocupaciones.

- Creación de archivos Javascript Aparentemente, las características de minificación vienen en .NET 4.5 . Si sigue la ruta discreta, no debería haber nada que le impida cargar todo su JS en 1 archivo de script. Tendría cuidado al crear diferentes archivos JS para cada tipo de entidad, terminarás con una explosión de archivos JS. Recuerde, una vez que se carga su archivo de script, el navegador debe almacenarlo en caché para futuras solicitudes.

- Consultas complejas que no considero que tengan características como paginación, clasificación, etc., como complejas. Mi preferencia es manejar esto con URL y lógica del lado del servidor, para hacer que las consultas de db sean tan limitadas como sea necesario. Sin embargo, estamos implementados en Azure, por lo que la optimización de consultas es importante para nosotros. Por ejemplo: /widgets/show-{pageSize}-per-page/page-{pageNumber}/sort-by-{sortColumn}-{sortDirection}/{keyword}. EF y LINQ to Entities pueden manejar la paginación y la clasificación con métodos como .Take (), .Skip (), .OrderBy () y .OrderByDescending (), para que obtenga lo que necesita durante el viaje db. Todavía no he encontrado la necesidad de un clientlib, así que honestamente no sé mucho sobre ellos. Busque otras respuestas para obtener más consejos al respecto.

- Proyecto seda Nunca he oído hablar de este, tendrá que echarle un vistazo. Soy un gran admirador de Steve Sanderson, sus libros, su BeginCollectionItem HtmlHelper y su blog. Dicho esto, no tengo ninguna experiencia con KnockoutJS en producción . He revisado sus tutoriales, pero trato de no comprometerme con algo hasta que sea al menos la versión 2.0. Como mencioné, se acaba de lanzar KnockoutJS 2.0.

- N-tier Si por nivel te refieres a una máquina física diferente, entonces no, no creo que nada salga por ninguna ventana. Generalmente 3 niveles significa que tiene 3 máquinas. Por lo tanto, es posible que tenga un cliente pesado como nivel de presentación, que se ejecuta en la máquina de un usuario. El cliente pesado puede acceder a un nivel de servicio, que se ejecuta en un servidor de aplicaciones y devuelve XML o lo que sea al cliente pesado. Y el nivel de servicio puede obtener sus datos de un servidor SQL en una tercera máquina.

MVC es una capa, en 1 nivel. Sus controladores, modelos y vistas son parte de su capa de presentación, que es 1 nivel en la arquitectura física. MVC implementa el patrón Modelo-Vista-Controlador, que es donde podría estar viendo capas adicionales. Sin embargo, trate de no pensar en estos 3 aspectos como niveles o capas. Trate de pensar en los 3 como preocupaciones de la capa de presentación.

Actualización después del comentario pres / bus / data

Bien, entonces estás usando niveles y capas de manera intercambiable. Usualmente uso el término "capa" para las divisiones lógicas / de proyecto / ensamblaje, y el nivel para la separación física de la red. Perdón por la confusion.

Encontrará bastantes personas en el campamento de MVC que dicen que no debe usar los "Modelos" en MVC para su modelo de datos de entidad, ni debe usar sus Controladores para la lógica de negocios. Idealmente, sus modelos deben ser ViewModels específicos de la vista. Usando algo como Automapper, tomas tus entidades de tu modelo de dominio y las DTO en ViewModels, esculpidas específicamente para su uso por la vista.

Cualquier regla de negocio también debe ser parte de su dominio, y puede implementarla utilizando servicios de dominio / patrón de fábrica / lo que sea apropiado en su capa de dominio, no en la capa de presentación MVC. Los controladores deben ser tontos, aunque no tan tontos como los modelos, y deben responsabilizar al dominio por cualquier cosa que requiera conocimiento comercial. Los controladores administran el flujo de solicitudes y respuestas HTTP, pero cualquier cosa con valor comercial real debe estar por encima de la calificación salarial del controlador.

Por lo tanto, aún puede tener una arquitectura en capas, con MVC como capa de presentación. Es un cliente de su capa de aplicación, capa de servicio o capa de dominio, dependiendo de cómo lo haya diseñado. Pero en última instancia, su modelo de entidad debe ser parte del dominio, no modelos en MVC.

danludwig
fuente
Estoy totalmente de acuerdo con esta respuesta! Especialmente: • Resharper es un genio MVC ... desde la verificación de errores hasta la navegación IDE, ¡su utilidad me deja boquiabierto! • MVC del lado del servidor es casi siempre el mejor enfoque • MVC no tiene 3 niveles separados, es una sola capa de presentación. Nunca lo pensé de esta manera, pero es absolutamente correcto.
Scott Rippey
Muy buena respuesta, definitivamente lo que estaba buscando a costa de mi 300 rep. Las bebidas están sobre mí si estás en el área de Toronto :)
Por cierto, siempre consideré N-tier como Pres / Bus / Data, independientemente de dónde se sentaran físicamente. Es por eso que dije que MVC casi elimina esa arquitectura porque básicamente combina los 3, lo que dijiste algo de acuerdo con eso, pero también da una perspectiva diferente al respecto.
Advertiría contra el modelo ViewModel, modelo por vista. Recientemente me encontré con una situación en la que más tarde deseé no tener esta abstracción de DTO a ViewModel. Ver: stackoverflow.com/q/7181980/109456
Como regla general, no me gusta ver jQuery y, en su lugar, escribir objetos con interfaces que cualquier desarrollador del lado del servidor podría entender con bastante rapidez con JQ o la API DOM haciendo el negocio dentro. También me gusta mucho el concepto URLConfig de Django y lo he encontrado útil para configurar objetos para la implementación en páginas. No tengo idea de lo que el MV? Se supone que las bibliotecas deben hacer por mí. No encajan perfectamente con el problema, IMO y la delegación de eventos DOM + es todo el modelo que necesito para manejar páginas sin estar excesivamente vinculado a una estructura específica.
Erik Reppen
6

No voy a escribir una respuesta completa, pero quiero compartir algunos consejos.

Mis consejos

1. Estructura del proyecto
He descubierto que la estructura MVC predeterminada no es buena para mí. Generalmente trabajo al mismo tiempo en el controlador, las vistas y el modelo de la misma entidad (piense en el producto, pedido, cliente). Entonces, me gusta tener los archivos en la misma carpeta, pero con diferentes espacios de nombres.

2. Datos
Si utiliza Linq-to-SQL o EF, se arrepentirá más tarde.
Uso PetaPoco que me permite ejecutar SQL recuperando y actualizando registros sin la molestia de mapeo, pero sin aprender una nueva forma de hacer las cosas y sin las pesadillas de rendimiento.

Tengo un generador de código para crear la clase POCO inicial con los atributos de PetaPoco, y luego cambiar la clase cuando se agrega o elimina algún campo.

PetaPoco funciona con clases dinámicas y estándar, por lo que no tiene ningún compromiso (Massive es todo dinámico y Dapper todas las clases estándar)

También genero un SQL maestro , usando el SqlBuilder incorporado, que contiene todas las uniones estándar para la entidad, pero no DONDE, así que reutilizo el mismo SQL para recuperar una entidad o una lista.

3. Jquery Puede estandarizar algunas partes de la interfaz de usuario utilizando una llamada general de jQuery (rellenando algunos datos dentro del elemento HTML).

Por ejemplo, tengo esto para eliminar.

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

Solo necesito agregar la clase jbtn-borrara un hipervínculo, y muestra un cuadro de diálogo, eliminar el registro y ocultar eltr

Pero no lo pienses demasiado. Su aplicación brillará con los pequeños toques en cada vista.

Cliente MVC vs. servidor MVC
Servidor MVC. Aproveche las vistas parciales que puede usar en el renderizado inicial y actualice algunas partes con Ajax usando la misma vista. Ver este excelente artículo

¿Cómo se deben manejar consultas complejas (permite llamar a un informe)
utilizo una clase que tiene los parámetros de informe como propiedades (propicios para utilizar MVC automapping) y un Generatemétodo que ejecuta la consulta y llenar una lista de una clase personalizada (si no no tiene una clase que se ajuste al ViewModel)
. Puede usar esta clase como modelo de la vista y llenar la tabla con la lista generada.

Proyecto Silk de Microsoft
sobrearquitecturado. Corre tan rápido como puedas en la dirección opuesta.

Eduardo Molteni
fuente
Es curioso, mientras leía Project Silk seguía teniendo este sentimiento molesto y no podía ubicarlo. Overarchitected podría haber sido eso ...
3

1. Estructura del proyecto

Tengo 2 archivos de proyecto en mi solución

1) Capa de servicio / negocio Pongo toda mi lógica de negocios y código de acceso a base de datos y POCO en este proyecto separado. No necesita una capa de acceso a datos si usa un ORM ya que el ORM ya abstrae la capa DB.

2) La capa de IU contiene todas mis vistas, controladores, modelos, scripts, CSS

Intento hacer que mis controladores, vistas, scripts y CSS utilicen una estructura de carpetas similar. También estructurar mis archivos para que coincidan con la ruta de la URL tanto como sea posible. Para evitar tener que escribir rutas personalizadas.

Utilice DisplayTemplates, EditorTemplates, vistas parciales y la carpeta Shared tanto como sea posible.

Luego estructuro todos mis Scripts para que coincidan con las mismas Áreas, Controladores de mis archivos c # Para tener un archivo common.js en la raíz, un archivo js por página y un archivo common.js para cada área.

Archivos CSS Normalmente tengo 2 + n (donde n es el número de áreas) 1er archivo CSS es CSS solo para la página de destino solo para ayudar con un tiempo de carga de página más rápido (probablemente no tan importante para el entorno empresarial / corporativo) 2do archivo CSS es un archivo common.css que tiene todos los estilos para todas las demás páginas. Luego, otro archivo common.css para cada área, por ejemplo, un archivo AdminArea.css que tiene CSS para cada página de administración.

2. Acceso a datos

Si uso Entity Framework, uso CodeFirst, ya que funciona muy bien con POCOS y no tiene un modelo que mantener. nHibernate es mucho más poderoso pero tiene una curva de aprendizaje más pronunciada. Para la paginación de los resultados de la base de datos, tengo una clase util c # reutilizable y una vista parcial que uso para todas mis vistas.

Para consultas complejas y generación de informes, uso procedimientos almacenados. Son mucho más fáciles de escribir y mantener y ofrecen más potencia al LINQ. También pueden ser reutilizados por otros servicios como SSRS. Utilizo automapper para convertir el conjunto de datos devuelto al mismo marco de POCO que utiliza.

3. Organización del código del lado del cliente y representación de la interfaz de usuario

La respuesta de Eduardo Molteni tiene un buen código de ejemplo. Además, definitivamente recomendaría usar knockoutjs ya que tiene buenas plantillas y enlaces. Si usa JSON para todas sus llamadas AJAX, que uso mucho, entonces tener el mapa automático de la interfaz de usuario para los objetos JS es un gran ahorro de tiempo.

Preguntas generales

Las consultas complejas deben vivir en un proceso almacenado. (ver comentario de emeraldcode.com)

Aún conserva su arquitectura de N niveles usando este MVC.

Daveo
fuente
1

Recientemente me conmovió creer que, si planea utilizar las tres tecnologías que enumeró, primero debe comenzar asumiendo la adopción de Orchard CMS . Creo que es la mejor respuesta individual a su requisito central:

¿Cuál es una estrategia óptima para organizar el código y la lógica mientras se mantiene la escalabilidad y la capacidad de crear una interfaz de usuario rica, rápida y limpia?

En el escenario de Ochard, todo lo que no puede abordar a través de sus mecanismos de configuración lo manejaría a través de la adición de módulos en línea gratuitos o escribiendo su propio módulo (que por supuesto son C #, navaja, etc.). La organización del código es una fortaleza de Orchard.

En cuanto al acceso a datos, hay suficientes pros y contras para un ORM completo que también he llegado a pensar que un micro-ORM es la mejor opción. Prueba Massive o Dapper . Ambos aparecieron en Hanselminutes . Resumiré los dos diciendo esto: las abstracciones de SQL casi siempre se rompen a medida que un proyecto se amplía. Al final, la mejor solución para el acceso a la base de datos es esta abstracción llamada SQL (poco sarcasmo, pero cierto). Deje que el micro-ORM trabaje con eso y obtendrá oro.

Pon Orchard junto con los micro-ORM, y puedes cortar acero como mantequilla. Er, lo que significa que puede desarrollar rápidamente, escalar y tener un código que pueda ser fácilmente mantenido por un equipo que reciba la transferencia.

Brent Arias
fuente
0

No estoy seguro de cómo me perdí esta pregunta, pero agregaré mis dos centavos dos años después.

Cliente MVC vs. servidor MVC? Mi proyecto ya es una estructura MVC del lado del servidor, por lo que todavía hay una necesidad de MVC del cliente como Backbone.js.

MVC y MV? incluso antes de que se pusiera del lado del cliente, básicamente se ha convertido en un término de marketing que realmente solo promete que de alguna manera los datos se separarán de otras cosas, lo que en general es una gran idea, pero no es tan difícil de hacer. No importa qué enfoque esté tomando, justo antes o justo en el medio de hacer cambios en HTML que afecten las posibilidades de presentación o interacción, es el lugar más horrible para resolver lo que la empresa quiere que haga con los datos.

No hay nada especial en la "lógica de vista". El mismo principio debería aplicarse a toda lógica. Y es decir, no hagas nada ahora que hubiera tenido mucho más sentido hacer antes. Cuando todos sus patos están en una fila antes de pasar algunos datos o iniciar un nuevo proceso, es probable que la fase anterior sea mucho más reutilizable para cualquier otra cosa en el sistema que haga algo similar.

¿Deben crearse archivos Javascript para cada objeto (como un OrderHeader.js) y luego minimizarse / fusionarse durante la compilación? ¿O debería haber un Order.js que tenga lógica para OrderHeader, OrderDetails, Reports, etc.?

Realmente depende de usted, pero trataría de alejarme de la cuestión de un archivo y una clase. Nunca he entendido por qué fue útil, por ejemplo, tener que encontrar el archivo abstracto y la interfaz, y la implementación de los archivos, etc. Clasificar en asuntos más amplios. ctrl + f no es tan difícil de usar si dura un poco.

Dicho esto, nunca debes recombinar JS para hacer archivos más pequeños en la web. Los navegadores almacenan en caché JS, por lo que solo está forzando la recarga del mismo JavaScript al pegar JS antiguo en archivos nuevos. Salvo cantidades asombrosas de JavaScript, la única vez que no debería tener todo el JS en la página es cuando una cantidad muy grande que es altamente específica para una sección del sitio sin áreas grises / superpuestas nunca será necesaria en un determinado página.

Y FFS no se preocupa por la gestión de dependencias con JavaScript en la web. Require.js en sitios web de complejidad media a baja me dan ganas de club de focas bebé. Pegue sus bibliotecas de terceros en un bloque superior. Sus bibliotecas internas en el segundo bloque. Y luego su código de implementación (que nunca debería ser la décima parte de su código interno de la biblioteca, es decir, muy sucinto, claro y fácil de entender) en ese tercer bloque.

¿Cómo deben manejarse las consultas complejas? En este momento, mi teoría principal es / Informes / Pedidos por fecha / o algo por el estilo y uso una consulta SQL personalizada que representa un conjunto de datos personalizado (o ViewModel) en la Vista Razor. Pero, ¿qué pasa con la paginación, la clasificación, etc.? ¿Es mejor hacerlo por parte del cliente o del servidor? (suponga un conjunto de datos más grande: consulta SQL de 2 a 3 segundos) He leído a través de Project Silk de Microsoft. ¿Es este un buen camino a seguir? ¿Cómo se compara con Backbone.js u otros?

Honestamente, diría que lo que sea más fácil para usted que no apesta para el cliente. Las páginas web se cargan bastante rápido en la tecnología moderna. Si implementar en Ajax es muy doloroso para usted, no lo haga. Simplemente vaya con lo que mejor sabe y luego puede obtener fantasía más adelante y ver cómo le gusta para paginación. Si está creando una nueva aplicación compleja desde cero, comience con Essential y pulse Neat-o más tarde.

Estoy muy acostumbrado a una arquitectura de N niveles, ¿estos conceptos arrojan algo por la ventana? Parece que MVC es como un grupo de mini secciones en N niveles dentro de lo que hubiera sido el front-end o el nivel superior en el pasado.

¿Realmente depende de quién sea la idea de fantasía de qué MV? es. En mi opinión, lo del microcosmos tiende a funcionar muy bien. Una clase de widget que separa los datos, la comunicación y las cosas relacionadas con la vista internamente funciona muy bien. En la web del lado del cliente, lo más importante, la OMI, es mantener un equilibrio de mantener las preocupaciones separadas sin fragmentar innecesariamente en pequeñas preocupaciones cuyo reensamblaje dificulta la comprensión, la reutilización y la modificación de las cosas. La "POO" básica funciona muy bien aquí. No quieres procesos complejos. Es obvio que quieres cosas con nombre que se puedan mover y decir que hagan. Aquí hay algunos consejos en ese frente:

  • BESE esa interfaz (OOP) No quiero ver DOM o jQuery o cualquier otra cosa que un desarrollador del lado del servidor no pueda resolver con bastante rapidez en mi código de implementación. Todo lo que esa persona debería saber es qué clase aplicar en un contenedor div y qué cambiar para voltear para activar un conjunto bastante genérico de IU en una página determinada. Las variaciones sobre un tema aún deben lograrse pasando objetos de opciones bien documentados / comentados antes de que tengan que comenzar a mirar document.get <anything> o comprender algo más allá de los conceptos básicos más simples de CSS.

  • Bien, ¿cómo haces eso? Bueno, ya tenemos un modelo. Se llama DOM. Y tenemos delegación de eventos. Si no está cerrando indiscriminadamente el burbujeo de eventos (no haga eso, está ahí porque es útil), puede recoger cada uno de ellos incluso del cuerpo si lo desea. Luego, examine la propiedad de destino del objeto de evento pasado y determine quién acaba de "cubrir". Si está estructurando un documento HTML con sensatez, no hay razón para no usarlo como modelo de delegación. El comportamiento y la estructura del contenido están naturalmente vinculados. Está bien que los dos tengan identificadores superpuestos.

  • No pague por la vinculación de datos Y por "pagar" me refiero, por supuesto, a "colocar una biblioteca en su base de código que insista en que haga las cosas de manera justa, todo el tiempo para obtener un beneficio milagroso que en realidad no es difícil de hacer". El sistema de eventos de JQ lo hace bastante fácil.

Hora de ejemplo:

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!
  • No esconda la Web La principal fuente de engaño en todos los primeros intentos de facilitar el lado del cliente para el lado del servidor y los desarrolladores de aplicaciones depende de este punto crítico. Las solicitudes HTTP no son y nunca fueron complicadas. No requirieron una monstruosidad de 18! @ # $ Ing de nombre de evento confuso en cada etapa para que fuera más fácil de entender. Del mismo modo, hay mucho que saber sobre el lado del cliente, pero no hay razón para esconderse del HTML y el DOM que interactúa con él al colocar un gran modelo gigante encima. Ya es un gran modelo gigante y funciona muy bien. Todo lo que necesitamos para hacerlo un poco más manejable son algunas prácticas sensatas de OOP y algunos conocimientos de JS y DOM.

  • Favorecer la flexibilidad

EXTjs <==== flexibilidad escala ====> jQuery (no necesariamente ninguno de sus complementos)

En mi opinión, las herramientas que te permiten hacer bricolaje rápidamente son siempre la mejor opción. Las herramientas que lo hicieron todo por usted son solo la opción correcta cuando nadie por encima de su cabeza es particularmente exigente con los detalles y no le importa ceder el control a lo que se supone que debe ayudarlo. De hecho, he visto complementos que validan el HTML para asegurarse de que no se cuele un elemento diferente con los mismos rasgos de visualización exactos. ¿Por qué? Solo tengo teorías. Creo que todo se reduce a que los completistas realmente odian la idea de que alguien use sus cosas de una manera que no fue intencionada y eso siempre es inevitablemente lo que alguien quiere que hagas en la interfaz de usuario.

Erik Reppen
fuente