Modularidade Javascript, MVC baseado em servidor e realidade comercial


32

Entendo que essa é uma pergunta muito ampla, mas trabalhei com vários aspectos desse problema individualmente e estou lutando para reunir todos os conceitos e tecnologias.

Gostaria de especificar que as respostas devem incluir estas tecnologias:

  • C #
  • MVC 3 c / Navalha
  • Javascript com jQuery

Qualquer coisa acima e além daquelas (como Backbone.js , Entity Framework , etc.) são bem-vindas como sugestões, se ajudarem a responder à pergunta que é:

Usando as tecnologias listadas acima, qual é a melhor estratégia para organizar código e lógica, mantendo a escalabilidade e a capacidade de criar uma interface do usuário rica, rápida e limpa?

Idealmente, o foco deve ser colocado em uma solução que está sendo implantada em um ambiente comercial / corporativo. Nessa nota, a lista de tecnologias acima não será alterada, portanto, não ofereça soluções com "você deve usar xxx em vez de aaaa que está usando agora".

fundo

Trabalho com jQuery todos os dias, adotei o MVC do ASP.NET e trabalho com C # há muito tempo. Portanto, você pode apresentar soluções assumindo o conhecimento intermediário a avançado dessas tecnologias.

Organizarei a pergunta em partes menores para facilitar a resposta:

1. Estrutura do projeto

Dado que estou trabalhando com o ASP.NET MVC (no Visual Studio 2010 ), gostaria de uma solução de estrutura de diretório que ofereça alguma aceitação do layout principal desse tipo de aplicativo. Algo como o Brunch , suponho, mas com um pouco mais de detalhes sobre o que cada pasta conteria e como ela funciona com outras áreas do aplicativo.

2. Acesso a dados

Eu gostaria de modular meu acesso a dados o máximo que puder, com uma estrutura do tipo API. Você pode assumir muitas POCO objetos ( User, UserGroup, Customer, OrderHeader, OrderDetails, etc), mas também haverá alguns relatórios complexos que requerem dados SQL intensivo e renderização UI cuidado. A EF + LINQ é fantástica para o primeiro, mas não tanto para o último. Não consigo encontrar algo que pareça se encaixar nos dois cenários sem ser muito complicado ou muito simples.

3. Organização do código do lado do cliente e renderização da interface do usuário

Como a maioria dos desenvolvedores que adquiriu o jQuery pela primeira vez, caí na armadilha de misturar códigos onde quer que precisasse, mas rapidamente o achei acumulando e ficando feio. Embora eu tenha surgido aos trancos e barrancos desde então, ainda luto para modularizar meu código e trabalhar com várias partes da interface do usuário sem repetir o código.

Como exemplo, um pedaço de código típico que eu poderia escrever ficaria assim: comentei o que me incomoda ( observe que, desde então, mudei para o uso de chamadas AJAX adiadas e separei as solicitações de dados reais da manipulação do 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();
            }
        });
    }
});

Questões gerais

  • Cliente MVC vs. servidor MVC? Meu projeto já é uma estrutura MVC do lado do servidor, então ainda é necessário o cliente MVC como o Backbone.js fornece?
  • Os arquivos Javascript devem ser criados para cada objeto (como um OrderHeader.js) e depois minificados / mesclados durante a compilação? Ou deveria haver apenas um Order.jsque tenha lógica para OrderHeader, OrderDetails, Reportsetc?
  • Como as consultas complexas devem ser tratadas? No momento, minha teoria principal é /Reports/Orders-By-Date/ou algo parecido com isso e eu uso uma consulta SQL personalizada que renderiza um conjunto de dados personalizado (ou ViewModel) para o Razor View. Mas e quanto à paginação, classificação etc.? É melhor fazer isso do lado do cliente ou do servidor? (assuma um conjunto de dados maior - consulta SQL de 2 a 3 segundos)
  • Eu li o Project Silk da Microsoft . Este é um bom caminho a percorrer? Como ele se compara ao Backbone.js ou a outros?
  • Estou muito acostumado a uma arquitetura de camadas N, esses conceitos jogam isso fora da janela? Parece que o MVC é como um monte de mini seções N-camadas dentro do que teria sido o front-end ou a camada superior no passado.

Novamente, quanto mais específicas suas respostas, melhores serão. Eu li muitos documentos e exemplos de alto nível . Estou tentando entender melhor a tradução para exemplos do mundo real .


2
Você se esforça muito nessa questão, mas isso não me parece uma pergunta do Stackoverflow. Talvez a troca de pilha dos programadores seja mais adequada.
Pointy

3
Não discordo de que seja um tópico interessante, mas o Stackoverflow deve ser sobre questões objetivas . Algo parecido com essa pergunta é basicamente o garoto-propaganda de perguntas que "provavelmente solicitarão opinião, debate, argumentos, pesquisas ou discussão prolongada".
Pointy

8
Há um grupo de pessoas que planeja a maior escala o tempo todo, enquanto eu silenciosamente abro mão dos negócios, porque eles demoraram muito tempo planejando algo que nunca aconteceu.
Jason Sebring

1
Concordo com o @Pointy que isso pertence à pilha de programadores. Sua pergunta é muito interessante, e eu a seguirei porque estou sempre procurando conselhos. Mas não é uma questão objetiva, e só vai acabar em debates preferenciais. Como sempre, faça o que funciona melhor para sua situação ... nenhum de nós sabe nada sobre sua estrutura de rede, número de clientes ou estatísticas de tráfego ou processo de criação ... então a pergunta é MUITO vaga demais ... tudo o que sei é evite a seda. ;)
one.beat.consumer

1
Esta questão se encaixa na própria definição de "excessivamente amplo" e, portanto, "não é uma questão real". De qualquer forma, as perguntas individuais devem ser feitas como perguntas individuais com algum histórico leve (demais e as pessoas sinalizarão "não uma pergunta real"). No entanto, tenha cuidado, pois várias perguntas individuais provavelmente serão sinalizadas como "não construtivas" por si próprias; portanto, seria cuidadoso com o modo como você faz essas perguntas.
casperOne

Respostas:


10

Terry, meu amigo, você e eu devemos tomar uma bebida. Temos alguns problemas semelhantes.

1. Estrutura do projeto: concordo com Eduardo que a estrutura de pastas em um aplicativo MVC deixa algo a desejar. Você tem suas pastas padrão de Controladores, Modelos e Vistas. Mas a pasta Views é dividida em uma pasta diferente para cada Controlador, além de uma pasta compartilhada. E cada Views / ControllerName ou Views / Shared pode ser dividida em EditorTemplates e DisplayTemplates. Mas permite que você decida como organizar sua pasta Modelos (você pode fazer com ou sem subpastas e declarações adicionais de namespace).

Deus não permita que você esteja usando Áreas, que duplicam a estrutura de pastas Controladores, Modelos e Vistas de 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

Isso significa que, se você estiver trabalhando com algo como um WidgetController, precisará procurar em outras pastas para encontrar os respectivos WidgetViewModels, WidgetViews, WidgetEditorTemplates, WidgetDisplayTemplates, etc. essas convenções MVC. No que diz respeito a colocar um modelo, controlador e exibição na mesma pasta, mas com espaços para nome diferentes, evito isso porque uso o ReSharper. Irá sublinhar um espaço para nome que não corresponde à pasta em que a classe está localizada. Eu sei que poderia desativar esse recurso R #, mas ajuda em outras partes do projeto.

Para arquivos que não são de classe, o MVC fornece conteúdo e scripts prontos para uso. Tentamos manter todos os nossos arquivos estáticos / não compilados nesses locais, novamente, para seguir a convenção. Sempre que incorporamos uma biblioteca js que usa temas (imagens e ou css), todos os arquivos de tema ficam em algum lugar em / content. Para o script, apenas colocamos todos eles diretamente em / scripts. Originalmente, isso era para obter o JS intellisense do VS, mas agora que obtemos o JS intellisense do R #, independentemente da localização em / scripts, suponho que possamos nos afastar disso e dividir os scripts por pasta para melhor organizar. Você está usando o ReSharper? É ouro puro IMO.

Outro pequeno pedaço de ouro que ajuda muito na refatoração é o T4MVC. Usando isso, não precisamos digitar caminhos de string para nomes de áreas, nomes de controladores, nomes de ações e até arquivos de conteúdo e scripts. O T4MVC digita fortemente todas as seqüências mágicas para você. Aqui está uma pequena amostra de como a estrutura do seu projeto não importa tanto se você estiver usando o 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. Acesso a dados: Não tenho experiência com o PetaPoco, mas tenho certeza de que vale a pena conferir. Para seus relatórios complexos, você considerou o SQL Server Reporting Services? Ou você está executando em um banco de dados diferente? Desculpe, não sei ao certo o que exatamente você está pedindo. Usamos EF + LINQ, mas também colocamos certos conhecimentos sobre como gerar relatórios em classes de domínio. Portanto, temos o repositório de chamadas do serviço de domínio da chamada do controlador, em vez de ter o repositório de chamadas do controlador diretamente. Para relatórios ad-hoc, usamos o SQL Reporting Services, que novamente não é perfeito, mas nossos usuários gostam de poder trazer dados para o Excel facilmente, e o SSRS facilita isso para nós.

3. Organização do código do lado do cliente e renderização da interface do usuário: é aqui que acho que posso oferecer alguma ajuda. Veja uma página do livro de validação discreta do MVC e AJAX discreto. Considere isto:

<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 a função de sucesso do ajax por enquanto (mais sobre isso mais tarde). Você pode usar um único script para algumas de suas ações:

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

O código acima cuidará da confirmação, mostrando o botão giratório, mostrando a mensagem de espera e ocultando a mensagem giratória / de espera após a conclusão da chamada ajax. Você configura os comportamentos usando atributos data- *, como as bibliotecas discretas.

Questões gerais

- Cliente MVC vs. servidor MVC? Não tentei bibliotecificar as ações que você executou na função de sucesso, porque parece que seu controlador está retornando JSON. Se seus controladores estiverem retornando JSON, convém consultar o KnockoutJS. Knockout JS versão 2.0 foi lançada hoje . Ele pode ser conectado diretamente ao seu JSON, para que um clique observável possa vincular dados automaticamente aos seus modelos javascript. Por outro lado, se você não se importa em ter seus métodos de ação ajax retornando HTML em vez de JSON, eles podem retornar o UL já construído com seus filhos LI e você pode anexá-lo a um elemento usando data-myapp-response = "resultados". Sua função de sucesso ficaria assim:

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

Para resumir minha melhor resposta para isso, se você deve retornar o JSON de seus métodos de ação, está pulando a Visualização do lado do servidor, para que isso realmente não seja o MVC do servidor - é apenas o MC. Se você retornar PartialViewResult com chamadas html para ajax, este será o servidor MVC. Portanto, se seu aplicativo precisar retornar dados JSON para chamadas ajax, use o MVVM do cliente como o KnockoutJS.

De qualquer maneira, eu não gosto do JS que você postou porque combina seu layout (tags html) com comportamento (carregamento de dados assíncrono). A escolha do MVC do servidor com visualizações html parciais ou do MVVM do cliente com dados puros do modelo de visualização JSON resolverá esse problema, mas a construção manual de DOM / HTML em javascript viola a separação de preocupações.

- Criação de arquivo Javascript Aparentemente, os recursos de minificação estão chegando no .NET 4.5 . Se você seguir a rota discreta, não deve haver nada impedindo o carregamento de todo o seu arquivo de script JS in 1. Seria cuidadoso ao criar arquivos JS diferentes para cada tipo de entidade; você acabará com a explosão do arquivo JS. Lembre-se, uma vez que seu arquivo de script é carregado, o navegador deve armazená-lo em cache para solicitações futuras.

- Consultas complexas Não considero complexos como paginação, classificação etc. Minha preferência é lidar com isso com URLs e lógica do lado do servidor, para tornar as consultas de banco de dados tão limitadas quanto necessárias. No entanto, como estamos implantados no Azure, a otimização de consultas é importante para nós. Por exemplo: /widgets/show-{pageSize}-per-page/page-{pageNumber}/sort-by-{sortColumn}-{sortDirection}/{keyword}. EF e LINQ to Entities podem lidar com paginação e classificação com métodos como .Take (), .Skip (), .OrderBy () e .OrderByDescending (), para que você obtenha o que precisa durante a viagem ao banco de dados. Ainda não encontrei a necessidade de um clientlib, portanto, sinceramente, não sei muito sobre eles. Procure outras respostas para obter mais conselhos sobre isso.

- Projeto seda Nunca ouviu falar deste, terá que conferir. Sou um grande fã de Steve Sanderson, de seus livros, de BeginCollectionItem HtmlHelper e de seu blog. Dito isto, não tenho nenhuma experiência com o KnockoutJS em produção . Verifiquei seus tutoriais, mas tento não me comprometer com algo até que seja pelo menos a versão 2.0. Como eu mencionei, o KnockoutJS 2.0 foi lançado.

- Nível N Se por nível você quer dizer máquina física diferente, então não, acho que nada sai pelas janelas. Geralmente, em três níveis, você tem três máquinas. Portanto, você pode ter um cliente gordo como sua camada de apresentação, que é executada na máquina do usuário. O cliente gordo pode acessar uma camada de serviço, que é executada em um servidor de aplicativos e retorna XML ou qualquer outra coisa para o cliente gordo. E a camada de serviço pode obter seus dados de um servidor SQL em uma terceira máquina.

O MVC é uma camada, em uma camada. Seus controladores, modelos e visualizações fazem parte da sua Camada de apresentação, que é de 1 camada na arquitetura física. O MVC implementa o padrão Model-View-Controller, que é onde você pode ver camadas adicionais. No entanto, tente não pensar nesses três aspectos como camadas ou camadas. Tente pensar em todos os três como preocupações da camada de apresentação.

Atualização após comentário pres / bus / data

Ok, então você está usando camadas e camadas de forma intercambiável. Normalmente, uso o termo "camada" para divisões lógicas / projeto / montagem e camada para separação física de redes. Desculpe pela confusão.

Você encontrará algumas pessoas no campo do MVC que dizem que não deve usar os "Modelos" no MVC para o modelo de dados da entidade, nem usar os controladores para a lógica de negócios. Idealmente, seus modelos devem ser ViewModels específicos de exibição. Usando algo como o Automapper, você pega suas entidades do seu modelo de domínio e as DTO no ViewModels, esculpidas especificamente para serem usadas pela exibição.

Quaisquer regras de negócios também devem fazer parte do seu domínio, e você pode implementá-las usando serviços de domínio / padrão de fábrica / o que for apropriado em sua camada de domínio, não na camada de apresentação do MVC. Os controladores devem ser burros, embora não tão burros quanto os modelos, e devem dar responsabilidade ao domínio por qualquer coisa que exija conhecimento comercial. Os controladores gerenciam o fluxo de solicitações e respostas HTTP, mas qualquer coisa com valor comercial real deve estar acima da classe de pagamento do controlador.

Portanto, você ainda pode ter uma arquitetura em camadas, com o MVC como a camada de apresentação. É um cliente da sua camada de aplicativo, serviço ou domínio, dependendo de como você o arquitetou. Mas, em última análise, o modelo da sua entidade deve fazer parte do domínio, não dos modelos no MVC.


Eu concordo totalmente com esta resposta! Especialmente: • Resharper é um gênio do MVC ... desde a verificação de erros até a navegação no IDE, sua utilidade me impressiona! • O MVC do lado do servidor é quase sempre a melhor abordagem. • O MVC não possui três camadas separadas, é uma camada de apresentação única - nunca pensei nisso dessa maneira, mas é absolutamente correto.
Scott Rippey

Resposta muito boa, definitivamente o que eu estava procurando ao custo dos meus 300 representantes. As bebidas são por minha conta, se você estiver na área de Toronto :)

btw Eu sempre considerei a N-camada como Pres / Bus / Data, independentemente de onde eles estavam fisicamente. É por isso que eu disse que o MVC quase remove essa arquitetura porque combina basicamente o 3, o que você disse que concorda um pouco com isso, mas também fornece uma perspectiva diferente.

Eu alertaria contra a abordagem ViewModel, modelo por visualização. Recentemente, me deparei com uma situação em que depois desejei não ter essa abstração do DTO para o ViewModel. Veja: stackoverflow.com/q/7181980/109456

Como regra geral, eu não gosto de ver o jQuery e, em vez disso, escrever objetos com interfaces que qualquer desenvolvedor do lado do servidor seria capaz de entender rapidamente com o JQ ou a API do DOM que faz negócios dentro dele. Também gosto muito do conceito URLConfig do Django e achei útil para configurar objetos para implementação em páginas. Eu não tenho idéia do que o MV? bibliotecas deveriam fazer por mim. Eles não são adequados para o problema, a IMO e a delegação de eventos DOM + são todo o modelo de que eu preciso para lidar com páginas sem estar excessivamente vinculado a uma estrutura específica.
Erik Reppen

6

Não vou escrever uma resposta completa, mas quero compartilhar algumas dicas.

Minhas dicas:

1. Estrutura do projeto
Descobri que a estrutura MVC padrão não é boa para mim. Geralmente trabalho no controlador, nas visões e no modelo da mesma entidade (pense em produto, pedido, cliente) ao mesmo tempo. Então, eu gosto de ter os arquivos na mesma pasta, mas com espaços para nome diferentes.

2. Dados
Se você optar pelo Linq-to-SQL ou EF, se arrependerá mais tarde.
Eu uso o PetaPoco que me permite executar a recuperação e a atualização de registros do SQL sem a necessidade de mapear, mas sem aprender uma nova maneira de fazer as coisas e sem os pesadelos de desempenho.

Eu tenho um gerador de código para criar a classe POCO inicial com os atributos do PetaPoco e altero a classe quando algum campo é adicionado ou removido.

O PetaPoco trabalha com classes dinâmicas e padrão, para que você não tenha compromissos (o Massive é dinâmico e o Dapper, todas as classes padrão)

Também gero um SQL mestre , usando o SqlBuilder interno, que contém todas as junções padrão da entidade, mas nenhum WHERE, portanto, reutilizo o mesmo SQL para recuperar uma entidade ou uma lista.

3. Jquery Você pode padronizar algumas partes da interface do usuário usando uma chamada jQuery geral (preenchendo alguns dados dentro do elemento HTML).

Por exemplo, eu tenho isso para excluir.

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

Eu só preciso adicionar a classe jbtn-borrara um hiperlink e ele mostra uma caixa de diálogo, exclua o registro e oculte otr

Mas não pense demais. Seu aplicativo brilhará com pequenos toques em todas as visualizações.

Cliente MVC vs. servidor MVC
Server MVC. Aproveite as visualizações parciais que você pode usar na renderização inicial e atualize algumas partes com o Ajax usando a mesma exibição. Veja este excelente artigo

Como as consultas complexas devem ser tratadas (vamos chamá-lo de Relatório)
Eu uso uma classe que possui os parâmetros Report como propriedades (úteis para usar o MVC automapping) e um Generatemétodo que executa a consulta e preenche uma Lista de uma classe personalizada (se você não possui uma classe que se encaixa no ViewModel)
Você pode usar essa classe como modelo da visualização e preencher a tabela com a lista gerada.

Projeto Silk da Microsoft foi
superarquivado. Corra o mais rápido que puder na direção oposta.


Engraçado, ao ler o Projeto Silk, fiquei com essa sensação incômoda e não consegui identificá-la. Overarchitected pode ter sido que ...

3

1. Estrutura do projeto

Eu tenho 2 arquivos de projeto na minha solução

1) Camada de serviço / negócios Coloquei toda a minha lógica de negócios, código de acesso ao banco de dados e POCOs neste projeto separado. Não há necessidade de uma camada de acesso a dados se você estiver usando um ORM como o ORM já abstrai a camada de banco de dados.

2) A camada da interface do usuário contém todas as minhas visualizações, controladores, modelos, scripts, CSS

Eu tento fazer com que meus controladores, exibições, scripts e CSS usem uma estrutura de pastas semelhante. Também estruture meus arquivos para corresponder ao caminho da URL o máximo possível. Para evitar a necessidade de escrever roteamento personalizado.

Use os modelos DisplayTemplates, EditorTemplates, Parcial e a pasta compartilhada, tanto quanto possível.

Em seguida, estruturo todos os meus scripts para corresponder às mesmas Áreas, controladores dos meus arquivos c #. Assim, eu teria um arquivo common.js na raiz, um arquivo js por página e um arquivo common.js para cada área.

Arquivos CSS Eu normalmente tenho 2 + n (onde n é o número de áreas) O primeiro arquivo CSS é CSS apenas para a página de destino, apenas para ajudar com um tempo de carregamento de página mais rápido (provavelmente não tão importante para o ambiente comercial / corporativo) é um common.css que possui todos os estilos para todas as outras páginas. Em seguida, outro arquivo common.css para cada área, por exemplo, um arquivo AdminArea.css que possui CSS para todas as páginas de administração.

2. Acesso a dados

Se eu usar o Entity Framework, utilizarei o CodeFirst, pois funciona muito bem com o POCOS e você não tem um modelo para manter. O nHibernate é muito mais poderoso, mas possui uma curva de aprendizado mais direta. Para resultados de paginação de banco de dados, tenho uma classe util c # reutilizável e uma exibição patial que uso em todas as minhas visualizações.

Para consultas complexas e geração de relatórios, eu uso procedimentos armazenados. Eles são muito mais fáceis de escrever e manter e oferecem mais potência ao LINQ. Eles também podem ser reutilizados por outros serviços como o SSRS. Eu uso o automapper para converter o conjunto de dados retornado aos mesmos usos da estrutura de POCOs completos.

3. Organização do código do lado do cliente e renderização da interface do usuário

A resposta de Eduardo Molteni tem um bom exemplo de código. Além disso, eu recomendaria definitivamente o uso de knockoutjs, pois possui bons modelos e ligações. Se você usa JSON para todas as suas chamadas AJAX, as quais eu utilizo muito, ter o mapeamento automático da interface do usuário para os objetos JS economiza muito tempo.

Questões gerais

Consultas complexas devem residir em um processo armazenado. (veja o comentário emeraldcode.com)

Você ainda mantém sua arquitetura em camadas N usando esse MVC.


1

Recentemente, fui levado a acreditar que, se você planeja usar as três tecnologias listadas, deve começar assumindo a adoção do Orchard CMS . Acredito que é a melhor resposta única para o seu requisito central:

Qual é a estratégia ideal para organizar código e lógica, mantendo a escalabilidade e a capacidade de criar uma interface do usuário rica, rápida e limpa?

No cenário Ochard, qualquer coisa que você não possa resolver por meio de seus mecanismos de configuração, você lidaria com a adição de módulos on-line gratuitos ou com a criação de seu próprio módulo (que é claro, C #, razor, etc.). A organização do código é uma força do Orchard.

Quanto ao acesso a dados, há prós e contras suficientes em um ORM de nível completo que também passei a pensar que um micro-ORM é a melhor opção. Tente maciço ou Dapper . Ambos foram apresentados em Hanselminutes . Resumirei os dois dizendo o seguinte: abstrações do SQL quase sempre quebram à medida que um projeto aumenta. No final, a melhor solução para acesso ao banco de dados é essa abstração chamada SQL (pouco sarcasmo, mas verdadeiro). Deixe o micro-ORM trabalhar com isso e você terá ouro.

Coloque o Pomar junto com os micro-ORMs e você poderá fatiar aço como manteiga. Ou seja, você pode desenvolver rapidamente, escalar e ter um código que possa ser facilmente mantido por uma equipe que recebe a transferência.


0

Não sei como eu perdi essa pergunta, mas adicionarei meus dois centavos dois anos depois.

Cliente MVC vs. servidor MVC? Meu projeto já é uma estrutura MVC do lado do servidor, então ainda é necessário o cliente MVC como o Backbone.js fornece?

MVC e MV? mesmo antes de ser empurrado para o lado do cliente, basicamente evoluiu para um termo de marketing que realmente promete apenas que, de alguma forma, os dados serão separados de outras coisas, o que é em geral uma ótima idéia, mas não é tão difícil assim. Independentemente da abordagem adotada, logo antes ou logo no meio de fazer alterações no HTML que afetam as possibilidades de apresentação ou interação, é o lugar mais terrível para separar o que a empresa deseja que você faça com os dados.

Não há nada de especial em "visualizar lógica". O mesmo princípio deve se aplicar a toda lógica. E isto é, não faça nada agora que faria muito mais sentido antes. Quando todos os seus patos estão em fila antes de você passar alguns dados ou iniciar um novo processo, é provável que a fase anterior seja muito mais reutilizável para qualquer outra coisa no sistema que faça algo semelhante.

Os arquivos Javascript devem ser criados para cada objeto (como um OrderHeader.js) e depois minificados / mesclados durante a compilação? Ou deve haver apenas um Order.js que tenha lógica para OrderHeader, OrderDetails, Reports etc?

Depende realmente de você, mas eu tentaria me afastar da coisa de um arquivo e de uma classe. Eu nunca entendi por que foi útil, por exemplo, ter que encontrar o arquivo abstrato e a interface e os arquivos implementados, etc ... Categorizar sobre preocupações mais amplas. ctrl + f não é tão difícil de usar se demorar um pouco.

Dito isso, você nunca deve recombinar o JS para diminuir os arquivos na web. Os navegadores armazenam em cache o JS para que você esteja forçando as recargas do mesmo JavaScript colocando JS antigo em novos arquivos. Com exceção de quantidades impressionantes de JavaScript, o único momento em que você não deve ter todo o JS na página é quando uma quantidade muito grande dele é altamente específica para uma seção do site sem áreas sobrepostas / cinza nunca será necessária em um determinado página.

E o FFS não se preocupa com o gerenciamento de dependências com JavaScript na web. O Require.js em sites de média a baixa complexidade me faz querer bater selos de bebê. Coloque suas bibliotecas de terceiros em um bloco superior. Suas bibliotecas internas no segundo bloco. E então o seu código de implementação (que nunca deve ser um décimo, contanto que o código da sua biblioteca interna - ou seja, muito sucinto, claro e fácil de entender) nesse terceiro bloco.

Como as consultas complexas devem ser tratadas? No momento, minha teoria principal é / Reports / Orders-By-Date / ou algo nesse sentido e eu uso uma consulta SQL personalizada que renderiza um conjunto de dados personalizado (ou ViewModel) para o Razor View. Mas e quanto à paginação, classificação etc.? É melhor fazer isso do lado do cliente ou do servidor? (assuma um conjunto de dados maior - consulta SQL de 2 a 3 segundos) Eu li o Project Silk da Microsoft. Este é um bom caminho a percorrer? Como ele se compara ao Backbone.js ou a outros?

Honestamente, eu diria o que for mais fácil para você e que não cheira mal ao cliente. As páginas da Web carregam muito rápido na tecnologia moderna. Se implementar no Ajax é muito doloroso para você, não. Basta seguir o que você sabe melhor e, depois, pode ficar chique e ver como gosta na paginação. Se você estiver criando um novo aplicativo complexo a partir do zero, comece com essencial e aperte arrumado mais tarde.

Estou muito acostumado a uma arquitetura de camadas N, esses conceitos jogam isso fora da janela? Parece que o MVC é como um monte de mini seções N-camadas dentro do que teria sido o front-end ou a camada superior no passado.

Realmente depende da idéia fantasiosa de quem é o MV? é. Na IMO, a coisa do microcosmo tende a funcionar muito bem. Uma classe de widget que separa dados, comunicação e itens relacionados à exibição internamente funciona muito bem. Na Web do lado do cliente, o essencial, IMO, é manter um equilíbrio entre manter as preocupações separadas sem fragmentar desnecessariamente em pequenas e pequenas preocupações cuja remontagem dificulta a compreensão, a reutilização e a modificação das coisas. OOP básico "duh" funciona muito bem aqui. Você não quer processos complexos. Você quer, obviamente, coisas nomeadas que possam ser movidas e instruídas a fazer coisas. Aqui estão algumas dicas nessa frente:

  • BEIJE essa interface (OOP) Eu não quero ver o DOM ou jQuery ou qualquer outra coisa que um desenvolvedor do lado do servidor não possa descobrir rapidamente no meu código de implementação. Tudo o que essa pessoa precisa saber é qual classe colocar em um contêiner div e qual opção alternar para ativar um conjunto bastante genérico de interface do usuário em uma determinada página. Variações sobre um tema ainda devem ser realizadas passando objetos de opções bem documentados / comentados antes que eles comecem a olhar para document.get <anything> ou entender qualquer coisa além dos princípios mais básicos do CSS.

  • Ok, então como você faz isso? Bem, nós já temos um modelo. Chama-se DOM. E nós temos delegação de eventos. Se você não está desligando indiscriminadamente o evento de bolhas (não faça isso - está lá porque é útil), você pode escolher todos os itens, mesmo do corpo, se quiser. Em seguida, examine a propriedade de destino do objeto de evento passado e determine quem apenas 'quer que seja'. Se você estiver estruturando um documento HTML de maneira sensata, não há motivo para não usá-lo como modelo de delegação. O comportamento e a estrutura de conteúdo estão naturalmente ligados. Não há problema em que os dois tenham identificadores sobrepostos.

  • Não pague pela vinculação de dados E por "pagar", é claro, quero dizer "coloque uma biblioteca na sua base de código que insista em que você faça as coisas exatamente assim - o tempo todo, a fim de obter algum benefício milagroso que não é difícil de fazer". O sistema de eventos da JQ facilita bastante.

Hora do exemplo:

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!
  • Não esconda a Web A principal fonte de suckery em todas as primeiras tentativas de facilitar o lado do cliente para os desenvolvedores do lado do servidor e de aplicativos que dependem desse ponto crítico. Solicitações HTTP não são e nunca foram complicadas. Eles não exigiram uma monstruosidade de nome confuso-nome-evento-em-cada-fase da camada 18! @ # $ Para facilitar o entendimento. Da mesma forma, há muito a saber sobre o lado do cliente, mas não há razão para se esconder do HTML e do DOM que interage com ele, colocando um grande modelo gigante em cima dele. Já é um grande modelo gigante e funciona muito bem. Tudo o que precisamos para torná-lo um pouco mais gerenciável são algumas práticas sensatas de OOP e algum conhecimento de JS e DOM.

  • Favorecer a flexibilidade

EXTjs <==== escala de flexibilidade ====> jQuery (não necessariamente nenhum de seus plug-ins)

Na IMO, as ferramentas que permitem que você faça bricolage rapidamente são sempre a melhor escolha. As ferramentas que fizeram tudo isso para você são apenas a escolha certa quando ninguém na sua cabeça é particularmente exigente quanto aos detalhes e você não se importa em ceder o controle à mesma coisa que deveria ajudá-lo. Na verdade, vi plug-ins que validam o HTML para garantir que você não oculte um tipo diferente de elemento com as mesmas características de exibição exatas. Por quê? Eu só tenho teorias. Eu acho que tudo se resume a finalistas que realmente odeiam a ideia de alguém usar suas coisas de uma maneira que não era intencional e é sempre inevitavelmente o que alguém quer que você faça na interface do usuário.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.