Pessoal, estou pensando em montar um curso de ASP.Net MVC, com foco na tecnologia mas também com um fundo de melhores práticas. É um curso ainda sem precedentes no Brasil, e que só deve sair nos CPLSs da vida (Ka, BF, etc) em um ano mais ou menos, e mesmo assim em um estilo de treinamento que não acho que vai ter esse foco em boas práticas, ou material em português. Quero o feedback de vocês sobre a idéia, então votem, por favor, abaixo. Se o interesse for suficiente eu vou em frente e monto o curso.

Agradeço.


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 13 de novembro de 2008 às 20:02 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Você está envolvido em um projeto de ASP.Net MVC que vai para produção? Estou querendo sentir a adoção deste novo framework pela comunidade, então se você vai para produção com um projeto de ASP.Net MVC e puder compartilhar isso, me mande um e-mail em giggio [arroba] giggio.net, e me conte um pouco sobre o escopo do projeto e como ele ajudou você a solucionar um problema, quais as dificuldades enfrentou, e os prós e contras encontrados com relação a web forms. Compilando um número legal de exemplos vou postar aqui no blog os projetos em andamento e os resultados.

Já agradeço antecipado.


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 7 de novembro de 2008 às 05:39 | Tags:

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Estou um pouco atrasado… ainda estou me recuperando do Tech-Ed. Vamos lá:

O ASP.Net MVC entrou em beta no último dia 16, quinta-feira! Você pode baixá-lo aqui. Ainda não olhei nada direito, mas já vi que há comentários do Scott Hanselman e do ScottGu.

Batendo olho vi:

  1. Integração com JQuery (yey!), conforme eu esperava;
  2. Alguma integração com Silverlight;
  3. Melhorias na integração com o Visual Studio;
  4. Melhorias no Model Binder;
  5. Melkhorias no modelo de updates de objetos de negócio (vejam o TryUpdate aqui);
  6. Melhorias nas validações;
  7. Outras novidades, melhorias e refatorações gerais, e, pelo que vi, bem vindas.

Vou começar a blogar a respeito das novidades em breve, provavelmente no final da semana, ou no fim de semana, já que nesse momento estou fechando a .Net Magazine. Já posso adiantar que, para quem estava querendo trabalhar com o ASP.Net MVC e estava preocupado porque era preview ainda, agora não há mais preocupação. Imagino que pouco deve mudar entre agora e o RTW, já que no Beta eles não devem estar aceitando mais tanto feedback da comunidade.

Sinceramente, eu esperava um pouco mais de trabalho no ASP.Net MVC antes deste beta, preferia um release mais completo a um release mais cedo. De qualquer forma, com o release mais cedo a Microsoft passa a suportar oficialmente o ASP.Net MVC, o que encoraja muita gente a adotá-lo.

Será que agora no Beta o Visual Studio vai parar de desaparecer? Depois eu conto pra vocês.

E vocês, vão passar a usar o ASP.Net MVC agora?


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 21 de outubro de 2008 às 06:29 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tugwar-cabodeforca

Essa é uma pergunta frequente que recebo por e-mail ou às vezes em algum comentário aqui no blog: Quando devo usar ASP.Net MVC e quando devo usar Web Forms? Outra relacionada é: Quais os prós e os contras do ASP.Net MVC.

Vou tentar responder as duas perguntas considerando o estado atual do ASP.Net MVC, que é o release do Preview 5. Pode ser que até o lançamento, que ninguém sabe quando vai ser e que a Microsoft não comenta, as coisas mudem. Vamos lá.

Como eu sou um grande entusiasta deste novo framework, vou falar primeiro quando você deve usar, e seus prós. Você deve usar ASP.Net MVC quando:

  • Precisar mais controle sobre o HTML gerado do que o proporcionado pelos controles e as webpages de Web Forms. Todo o HTML gerado é você quem controla. Mesmo nos métodos de auxílio, quem decide se vai utilizá-los é você.
  • Quiser ter uma aplicação focada em padrões mais reconhecidos, inclusive no front-end. O padrão MVC é um padrão amplamente difundido e elogiado e é a base do ASP.Net MVC.
  • Precisar de um front-end que se integre melhor com padrões de arquitetura reconhecidos, como o DDD. O Web Forms também permite esse tipo de integração, mas com ASP.Net MVC eu diria que ela soa mais natural.
  • Quiser trabalhar com testes unitários também na interface com o usuário. Os controladores são totalmente testáveis, e como são eles que coordenam o fluxo de trabalho, é lá o maior foco dos testes.
  • Quiser utilizar já com o ASP.Net Routing, sem ter que esperar o ASP.Net 4.0. O ASP.Net MVC já nos possibilita utilizar o Routing de maneira muito inteligente, podendo gerar as rotas como bem quisermos.
  • Precisar de uma aplicação mais modular, inclusive no front-end. O ASP.Net MVC é muito bem dividido em módulos e partes.
  • Quiser ter mais liberadade para extender alguns pedaços do framework (essa é ligada à anterior). Com ASP.Net MVC você pode substituir os controllers, o engine de View, a maneira de procurar Views, o framework de testes, etc, etc, etc. No ASP.Net MVC a Microsoft seguiu a recomendação de programar para interfaces ou classes abstratas. Quase tudo é plugável.
  • Quiser utilizar XSLT, XML, texto puro, ou sei lá o que mais para renderizar as páginas web. Essa também segue da sua anterior. Com ASP.Net MVC, você pode gerar HTML utilizando Web Forms para sua View, mas não obrigatoriamente. Você pode utilizar outros motores de view para gerar o HTML.
  • Tiver a intenção de gerar uma página menor em bytes. ASP.Net MVC não tem viewstate, e o HTML é totalmente controlado por você, e isso torna a página menor.
  • Precisar ter dois forms HTML na mesma página. Isso é possível com ASP.Net MVC, mas não com Web Forms.

Quando você não deve utilizar o MVC, e deve seguir com Web Forms, ou seja, os contras do MVC e os prós do Web Forms. Você deve utilizar Web Forms quando:

  • Sua aplicação já está concluída (ou com boa parte pronta) com Web Forms. Não faça uma aplicação meio MVC, meio Web Forms. Apesar de tecnicamente viável vai confundir os desenvolvedores que vão dar manutenção no futuro, e durante o desenvolvimento vai dar mais trabalho ainda para separar rotas, entender quem chama o que, etc. Se já está com Web Forms, segue com Web Forms.
  • Tiver pouco tempo de desenvolvimento e a equipe não conhecer o padrão MVC, o framework ASP.Net MVC, ou os dois. Eu sei que em projeto nunca há tempo e tudo é para ontem, então essa recomendação deve ser usada com cautela. O ASP.Net MVC tem uma curva de aprendizado rápida, principalmente para que usou ASP3 (clássico e conhece bem o <%), portanto estou falando daqueles projetos que você já sabe que vai entrar para perder os finais de semanas e as noites.
  • Você gostar muito do modelo proporcionado pelo Web Forms de ilusão de manutenção de estado proporcionado pelo Viewstate. Agora com o P5 isso foi melhorado bastante (veja o post sobre validadores para ver um exemplo do que estou falando), mas para alguns acho que isso vai ser um deal breaker.
  • Precisar de controles muito inteligentes, que por enquanto, só o Web Forms tem. O calendário é o que me vem à mente de imediato. Pelo menos por enquanto vai te dar um bom trabalho fazer um calendário com ASP.Net MVC.  Pode ser que, agora que temos o Partial Rendering funcionando muito bem, alguma coisa venha por aí no formato de views parciais pré prontas. Seria ótimo. Se não vier agora, acredito que em algum momento esse tipo de coisa vai aparecer no ASP.Net MVC.
  • Suas necessidades de AJAX ou manipulação de Javascript forem muito altas, ou você odeia programar Javascript. No segundo caso eu recomendo o Script#, mas tem gente que nem assim vai querer. Nesse caso, pode ser que você não tenha a mesma flexibilidade que o Web Forms vai lhe dar, já que quase todo o código para o AJAX e o Javascript são gerados para você.
  • Você é fã de carteirinha de alguns controles complexos, como o gridview, os de membership, ou ainda, você gosta muito de databinding (arrasta o controle, chamada .Datasource, .Databind e acabou). Nesse caso você vai se sentir fazendo muito trabalho manualmente e pode não gostar. Lembre-se: não há, até o momento, web controls para ASP.Net MVC.
  • Você precisar utilizar programação de webparts para o Sharepoint. Quem conhece as webparts e sua integração com o Sharepoint sabe como essa integração é sensacional. Eu duvido que seja possível bater esse nível de integração na versão 1.0 do ASP.Net MVC.

Lembrem-se que Web Forms é um produto com 6 anos de lançado, e 8 de desenvolvimento, enquanto o ASP.Net MVC nem foi lançado ainda. O Web Forms é uma tecnologia muito madura, que já atende maravilhosamente os anseios da comunidade de desenvolvimento, e já foi muito lapidado de lá para cá. Ainda assim, eu estou vendo o ASP.Net MVC como um framework que já tem que sair um pouco amadurecido, ou a comunidade vai demorar a adotá-lo, em vista do grande sucesso e da enorme facilidade trazidos pelo Web Forms.

O que vocês acham? Os seus novos projetos têm mais cara de ASP.Net MVC ou Web Forms?


Postado na(s) categoria(s) ASP.Net MVC pelo Giovanni Bassi em 9 de outubro de 2008 às 20:17 | Tags:

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

O webcast de ASP.Net MVC foi remarcado para amanhã, quarta-feira, por motivo de força maior. Vejo vocês lá.


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 7 de outubro de 2008 às 17:03 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Pessoal, há algum bug nos templates do Preview 5 do ASP.Net MVC que faz com que o Visual Studio desapareça do nada quando você vai editar um arquivo ASPX, ou .master. Não há mensagem alguma, ele só desaparece. Se você procurar um pouco, vai achar no seu Event Viewer o seguinte:

“.NET Runtime version 2.0.50727.3053 - Fatal Execution Engine Error”

Não adianta fechar e abrir o Visual Studio. Na próxima abertura ele vai cair na hora que o projeto carregar. Na carga seguinte então ele desabilita a carga automática dos últimos arquivos abertos, mas se você tentar abrir ele some de novo.

Para resolver:
Mais simples do que eu imaginava. Apague sua pasta bin e recompile.

Lembrando: ASP.Net MVC não é nem Beta ainda, então, muita calma com as pedras que vocês vão jogar.


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 6 de outubro de 2008 às 21:56 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Pessoal, lembrando que amanhã (terça-feira, 7/10) tem webcast de MVC avançado ao meio dia, ao vivo.

Estou relembrando porque algumas pessoas fizeram contato comigo depois do último webcast dizendo que tinham esquecido da data.

Vejo vocês lá.


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 6 de outubro de 2008 às 17:09 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

(Este aqui é o quarto post sobre as novidades do Preview 5 (P5) do ASP.Net MVC. Mais informações aqui e aqui.)

Vou falar neste post de um conceito que já tinha umas sementes plantadas no Preview 4 e que é bem interessante: Partial Rendering.

Partial Rendering é a habilidade que você tem de pegar pedaços de interface gráfica e incluir na sua View. Por exemplo, você pode incluir um menu, um footer, um header, o que achar melhor. O conceito é meio parecido com web controls, mas não é a mesma coisa. Web controls, para o MVC, são simples geradores de html, são views tanto quanto uma página aspx. E os dois, páginas e web controls, podem ser usados como views, tanto para renderização completa, quanto para parcial.

Você pode confirmar isso criando uma ação simples, e, para a view, em vez de criar uma aspx, crie um ascx, com o mesmo padrão de nomes. Vai rodar e vai funcionar. A diferença é que controles não tem todo o código html por padrão, então vai sair sem <html>, sem <body>, sem <head>, etc. Mas vai sair. O ideal é, quando utilizar o view engine do webforms, utilizar controles para renderização parcial, e páginas para renderização completa.

E como funciona a renderização parcial? De forma muito simples. Você chama o método RenderPartial da classe HtmlHelper, passa o nome da view, opcionalmente também o modelo e o dicionário de dados da view. Se você não passar esses opcionais o ASP.Net sozinho vai passar os mesmos objetos que a view que está chamando recebeu. Ou seja, é bom verificar, porque se você não indicar qual o modelo, pode receber um erro.

Abaixo está o código da página Index.aspx, que vem com o MVC. Alterei ela para utilizar um modelo diferente, do qual já vou falar. Vejam a declaração da página:

public partial class Index : ViewPage<Models.ModeloComposto<DateTime>>

Abaixo as classes de modelo que criei:

public class ModeloComposto
{
    public IList<Aniversariante> AniversariantesDoMes { get; set; }
}
 
public class ModeloComposto<T> : ModeloComposto
{
    public T ModeloCustomizado { get; set; }
}

Vejam que criei um modelo composto, para facilitar. Estou assumindo que todas as views da aplicação dependem de um dado comum, que coloquei na classe ModeloComposto. Essa classe vai ser alterada conforme eu precise de mais dados, como um footer customizado, onde eu incluiria uma propriedade string. Neste exemplo estou assumindo que toda página teria um widgetzinho que exibiria os aniversariantes de hoje, e para isso ser possível, preciso ser capaz de passar essa informação à view, e é isso que estou fazendo.

Já a classe genérica ModeloComposto<T> estou usando para poder estender a classe que contém as propriedades compartilhadas. Por exemplo, minha view Index utiliza uma ModeloComposto<DateTime>, ou seja, o seu modelo mesmo é um objeto do tipo data, mas ela também recebe os outros comuns. Views simples, como a About, que não têm modelo próprio (são quase estáticas), utilizam a primeira classe. As que precisarem de modelo próprio utilizam a classe genérica.

Vejam o controlador como ficou:

public ActionResult Index()
{
    ViewData["Title"] = "Home Page";
    ViewData["Message"] = "Welcome to ASP.NET MVC!";
    var modelo = new Models.ModeloComposto<DateTime>() 
    { 
        AniversariantesDoMes = Models.Aniversariante.ObterAniversariantesDoMes(), 
        ModeloCustomizado = DateTime.Now 
    };
    return View(modelo);
}

Notem que crio a classe de modelo composto, e passo à ela a data atual. Na propriedade comum, de aniversariantes, passo os aniversariantes via um suposto método de negócio (simples, somente para exemplo). Vejam o resto da View:

<h3>
    Hoje é dia <% =ViewData.Model.ModeloCustomizado.ToShortDateString() %>
</h3>
 
<% Html.RenderPartial("Aniversarios", this.ViewData.Model.AniversariantesDoMes); %>

O modelo é uma simples data, e é utilizado, via propriedade ModeloCustomizado para exibir a data atual. Nada de mais aí.

O interessante mesmo é o método RenderPartial. Notem que passo a ele que quero renderizar parcialmente a View “Aniversarios”. Isso vai executar esta view e colocar o resultado desta view neste exato ponto. Era o que eu queria. Estou passando também os dados de aniversariantes do mês como modelo.

Vejam o código da ascx:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Aniversarios.ascx.cs" 
Inherits="MvcApplication2Preview5.Views.Home.Aniversarios" %>
<h5>Aniversariantes:</h5>
<table>
    <tr>
        <td>Nome</td>
        <td>Idade</td>
    </tr>
    <% foreach (var aniversariante in this.ViewData.Model)
       {
    %>
        <tr>
            <td><% =aniversariante.Nome %></td>
            <td><% =(DateTime.Now.Year - aniversariante.DataNascimento.Year)
                    .ToString() %></td>
        </tr>
 
    <%      
       } %>
</table>

E logo abaixo a declaração da classe do controle:

public partial class Aniversarios : ViewUserControl<IList<Models.Aniversariante>>

Resumindo: o controle utiliza uma lista de aniversários, que recebe da view principal, que por sua vez recebe de uma view composta enviada pelo controlador. O controle não sabem que o está chamando, mas sabe o que fazer com o modelo, da mesma forma que a página aspx.

O resultado, simples, fica assim:

Página com resultado de view parcial

Bem interessante, certo? Tenho certeza que isso vai ajudar muito. E o legal é que o conceito de MVC e separação de responsabilidades está mantido. A responsabilidade das views continua sendo, somente, exibir os dados e interagir com o usuários, passando todo o controle aos controladores.

Preciso agora só abordar um aspecto interessante: quem deveria estar recebendo os dados na verdade não é cada View, mas a Master. E eu sei que a Master pode ser tipada por modelo também. Esse vai ser o caso de uso mais comum. Vou buscar isso e conto para vocês em seguida. Não tem a ver com o P5, mas é interessante. Falo de isso em breve. Até lá.


Postado na(s) categoria(s) ASP.Net MVC pelo Giovanni Bassi em 5 de outubro de 2008 às 19:20 | Tags:

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

(Este aqui é o terceiro post sobre as novidades do Preview 5 (P5) do ASP.Net MVC. Mais informações aqui e aqui.)

Calma, meus amigos… como tudo no ASP.Net Mvc, a idéia é a mesma, mas a implementação é mais “unplugged”, mais hardcore! Eu sei que todos estão esperando os validadores, já estamos no Preview 5 (!), então vamos lá.

O conceito aqui é de validação, mas não teremos controles validadores, em que você indica que quer validação de datas e ele faz, ou que um campo é obrigatório e o javascript já é gerado para você. A validação, pelo menos até agora, acontece toda no servidor, e o cliente só exibe os erros de validação e as mensagens. Mas acompanhem comigo a implementação. Vou comentado ao longo do post.

O conceito é o seguinte: você tem um campo “x” de algum objeto de negócio. O servidor valida este campo contra alguma regra física (tipo, nulabilidade, etc) e/ou de negócio (deve ser maior o campo “y”, só pode ser nulo se o campo “w” também for, etc). Se houver um problema o cliente recebe a página de volta, corretamente preenchida, e com indicação dos campos incorretos, com mensagens, inclusive. Essa parte ficou parecida ao Webforms, há o conceito do validador que gera o * ao lado do campo com problema, e do summary de validação, mas eles são diferentes. Vamos aos screenshots:

Entrada de dados:

Input simples

Campo com erro após o submit. Notem que os valores voltam conforme foram digitados, mesmo os incorretos. Neste caso, que é um cadastro de categorias, é obrigatório a categoria tenha descrição e nome:

Primeiro erro de validação sem summary

Agora utilizando a exibição com summary (notem os asteriscos também):

Segundo erro de validação com summary

Tudo isso é meio automático. Meio, não muito. Vejam o código do formulário de edição:

    1 <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
    2 AutoEventWireup="true" CodeBehind="Edit.aspx.cs" 
    3 Inherits="MvcApplication1Preview5.Views.Categories.Edit" %>
    4 <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    5 <% using (Html.Form())
    6    { %>
    7    <% =Html.ValidationSummary() %>
    8    <table>
    9     <tr>
   10         <td>Category Name:</td>
   11         <td>
   12             <% =Html.TextBox("CategoryName") %>
   13             <%--<% =Html.ValidationMessage("CategoryName") %>--%>
   14             <% =Html.ValidationMessage("CategoryName","*") %>
   15         </td>
   16     </tr>
   17     <tr>
   18         <td>Description:</td>
   19         <td>
   20             <% =Html.TextBox("Description") %>
   21             <%--<% =Html.ValidationMessage("Description")%>--%>
   22             <% =Html.ValidationMessage("Description", "*")%>
   23         </td>
   24     </tr>
   25    </table>
   26 <% =Html.SubmitButton("Enviar","Enviar") %>
   27 <% } %>
   28 </asp:Content>

(Notem o novo método “Html.Form”, com overload sem parâmetros. Ele vai postar de volta para o mesmo controlador e mesma ação, algo desejável depois da possibilidade de postar para ações com o mesmo nome.)

É bastante simples. Esse é o código com o summary incluido. Continuando no mesmo caminho, a utilização dos validadores é feita com métodos de auxílio (helper methods), a partir da classe HtmlHelper. São dois os métodos: ValidationMessage, para as mensagens, e ValidationSummary, para o summary. O método ValidationMessage tem um overload em você passa o nome do campo com problema (está comentado no código acima), e tem outro que você passa o nome do campo e o texto a ser exibido. Se você passar este segundo parâmetro, como estou fazendo quando passo só um asterisco “*”, a mensagem de erro não é exibida, só o que você digitou neste segundo campo. E se você tiver uma chamada ao método ValidationSummary, é lá que os erros que você ocultou são exibidos. Não é obrigatório ter o summary e o message juntos, você pode ter só o ValidationMessage, ou só o ValidationSummary, mas os dois juntos ficam melhores.

Nesse momento você, assim como eu também pensei quando vi, deve estar pensando: e de onde vem esta informação de erros de validação? Não há no MVC nenhum lugar em que se armazena isso. Não havia. Agora há. Chama-se ModelState, e é uma classe nova no MVC. Lá você coloca erros o valor que foi tentado. Há também um dicionário (chamado ModelStateDictionary), onde você indica o campo como chave em string, e o ModelState deste campo como valor. Fica então fácil fazer coisas desse tipo:

modelState.AddModelError("CategoryName", cat.CategoryName, 
"O valor de CategoryName é obrigatório.");

Essa classe é acessível a partir do ViewData. Há uma propriedade chamada ModelState (que na verdade é um ModelStateDictionary), que você pode manipular. E se está na View o Controller enxerga e pode manipular. E é a partir dele mesmo que rola toda a coordenação. Afinal, é trabalho do controlador dizer o que a view deve exibir.

Existe um motivo para a complexidade adicional que é colocar os erros de validação no modelo: É PORQUE É LÁ QUE ELES DEVEM FICAR. Eu sei que quando usamos webforms quem controla a exibição dos erros de negócio são os validadores diretamente, ou seja, a interface final com o usuário (ou UI, user interface). Pois é, isso traz altíssimo acomplamento, dependência da camada de negócio da camada de interface gráfica (o correto é o contrário), e uma separação de responsabilidades pobre. Funciona? Funciona. Mas, se você não validar no modelo de novo, pode ter problemas. E se validar, está indo contra o famoso princípio DRY (Don’t Repeat Yourself, ou, não se repita). E a manutenção passa a ficar um inferno, porque as regras de negócio estão espalhadas por toda a aplicação. É por isso que sempre digo que essa nova maneira de trabalhar enfatiza as boas práticas. ASP.Net MVC é o que há!

Discursos a parte, o que eu fiz para controlar os erros foi simples, foi mais para simplificar o exemplo. O ScottGu tem um exemplo um pouco diferente, mais complexo, com uso de interfaces, sugiro dar uma olhada depois. Continuo utilizando o Entity Framework - EF (funciona bem, é rápido de montar, e está à mão). Ele gerou para mim uma classe Category, e eu criei uma parcial da mesma. Adicionei métodos parciais de validação, que já vêm criados quando a classe é gerada pelo EF, no caso os métodos OnCategoryNameChanging, e OnDescriptionChanging. Os dois acontecem antes da classe de categoria ser atualizada. Minha regra é simples: descrição e nomes são campos obrigatórios. Se vierem em branco ou nulos é um erro, e eu lanço uma exceção. Assim:

    1 [ModelBinder(typeof(Binders.CategoryBinder))]
    2 public partial class Category
    3 {
    4     partial void OnCategoryNameChanging(string value)
    5     {
    6         if (string.IsNullOrEmpty(value))
    7         {
    8             LancaErro("O valor de CategoryName é obrigatório.");
    9         }
   10     }
   11     partial void OnDescriptionChanging(string value)
   12     {
   13         if (string.IsNullOrEmpty(value))
   14         {
   15             LancaErro("O valor de Description é obrigatório.");
   16         }
   17     }
   18 
   19     private void LancaErro(string textoErro)
   20     {
   21         Erros.Add(textoErro);
   22         throw new ApplicationException(textoErro);
   23     }
   24 
   25     public IList<string> Erros = new List<string>();
   26 
   27 }

Eu não morri de amores com esse negócio de lançar exceção à toa, mas é o modelo recomendado. Isso tudo porque foi criado um novo método no ASP.Net MVC chamado TryUpdateModel, em que você passa a classe, ele já pega os erros, e cadastra no ModelStateDictionary, tudo sozinho, deixando a implemantação mais leve. Se der tudo certo ele retorna true. Se der algum erro ele retorna falso.(Há também o método UpdateModel, que retorna void, mas se não conseguir atualizar o modelo joga uma exceção.)

    1 [ActionName("Edit")]
    2 [AcceptVerbs("POST")]
    3 public ActionResult SaveEdit(int categoryID)
    4 {
    5     bool atualizou;
    6     Models.Category catFromDB;
    7     using (var db = new Models.NorthwindEntities())
    8     {
    9         catFromDB = (from cats in db.Categories
   10                         where cats.CategoryID == categoryID
   11                         select cats).First();
   12         atualizou = TryUpdateModel(catFromDB, 
               new[] { "CategoryName", "Description" });
   13         if (atualizou)
   14             db.SaveChanges();
   15     }
   16 
   17     if (atualizou)
   18         return RedirectToAction("Edit", new { CategoryID = categoryID });
   19     else
   20         return View(catFromDB);
   21 }

Viram a chamada do método na linha 12? Se não der erro eu atualizo o banco e volto para a view de edição, passando a própria categoria que recebi (que não foi alterada). Se der certo, eu redireciono para a edição de novo, para montar a tela de edição à partir de um GET, não de um POST.

Se estamos passando o objeto de categorias não modificado, como pode ser que o campo exibido para o usuário contém o valor digitado anteriormente, e não o valor do banco de dados? Isso é culpa do ModelState, que carrega a tentativa, lembram? Agora, todos os métodos do HtmlHelper estão passando a checar o ModelState. Se tiver um valor lá para um campo determinado ele é utilizado. Vejam o código retirado do método InputHelper, utilizado pelos outros métodos, como o Textbox(), para compor o html:

tagBuilder.MergeAttribute("value", attemptedValue ?? 
           ((useViewData) ? EvalString(name) : value));

Ou seja, se tem valor de tentativa, utilize.

E o fundo e bordas vermelhos? Mesma coisa, ModelState. Vejam outro trecho de código do mesmo método do HtmlHelper:

if (ViewData.ModelState.TryGetValue(name, out modelState)) {
    if (modelState.Errors.Count > 0) {
        tagBuilder.AddCssClass(ValidationInputCssClassName);
    }
}

Ou seja, se tiver um erro que seja, utilize uma classe de CSS. É isso que deixa o fundo e a borda vermelhos. Simples, não? A partir da inclusão do código do controlador, qualquer adição será trabalhada na View e na camada de negócios.

Nesse ponto fica devendo ainda algo que utilize Javascript, para facilitar a vida do usuário, sem postback. Aumenta a segurança, melhora a usabilidade, e diminui o uso da banda. Sinceramente, não sei se vamos ter esse presente, pode ser que não tenha. O foco em deixar tudo na camada de modelo, e ficar bem DRY pode impedí-los de caminhar nessa direção. Vamos ver.

Gostaria de ouvir a opinião de vocês. Gostaram do que viram? Dá muito trabalho? O ScottGu, no post que comentei, relembra que o webforms não vai morrer, e o MVC e o webforms vão continuar evoluindo em paralelo, e lembra: se você não quiser, não precisa usar o MVC. O que você acha? Vale a pena? Dá para abandonar o webforms?

O projeto que usei está disponível aqui.


Postado na(s) categoria(s) ASP.Net MVC pelo Giovanni Bassi em 3 de outubro de 2008 às 08:15 | Tags:

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

countdown Pessoal, depois do webcast sobre o CTP 4 do ASP.Net MVC, vou fazer um novo webcast sobre ASP.Net MVC, em parceria com o time do MSDN. Desta vez abordarei recursos avançados. Vejam a descrição:

Nesse webcast veremos como utilizar algumas funções avançadas do ASP.Net MVC. Falaremos sobre a arquitetura do ASP.Net MVC, veremos a coleção TempData, o que são e como criar InterceptionFilters, como criar testes unitários, como e porque utilizar tipos complexos nas ações, e como realizar validação de campos. Os exemplos utilizarão o Entity Framework como modelo.

O webcast vai ser na próxima terça-feira, dia 7 de outubro, ao meio dia.

O link para inscrição é:

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032391566&culture=pt-BR

Aproveite para participar e tirar suas dúvidas com relação aos conceitos que vão ser apresentados, já que tem uma interação bem legal para quem assiste na hora. E no final, geralmente rola um sorteio.

Vejo vocês lá.

Observação: Se você não viu o anterior, não tem acompanhado as séries de POSTs sobre MVC aqui no blog, ou em outro lugar, sugiro assistir o webcast anterior, e também um que o Rogerio Cordeiro, da Microsoft, fez um pouco antes, introduzindo o MVC.


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 2 de outubro de 2008 às 18:09 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Continuando com a série sobre o Preview 5 do ASP.Net MVC, vou falar agora de uma das features mais legais dessa nova versão, que é a possibilidade de utilizar tipos complexos nos métodos dos controladores. (Vou continuar no exemplo da tabela de categorias do banco Northwid.) Por exemplo, antes, para salvar uma categoria nova, o método seria o seguinte:

[ActionName("Create")]
[AcceptVerbs("POST")]
public ActionResult Save(string CategoryName)
{
    var cat = new Models.Category();
    cat.CategoryName = CategoryName;            
    var db = new Models.NorthwindEntities();
    db.AddToCategories(cat);
    db.SaveChanges();
    db.Dispose();
    return RedirectToAction("Index");
}

Se eu quisesse salvar também a descrição, já teria que mudar a assinatura do método:

public ActionResult Save(string CategoryName, string Description)

Já começou a complicar… Para facilitar isso tudo, que tal utilizar um objeto complexo, um objeto de negócio, do domínio da aplicação? Poxa, faz bem mais sentido. Nesse caso, estou utilizando o Entity Framework, que tal usar a própria classe de categoria do EF? Em vez de ficar criando a categoria e adicionando os valores um a um:

var cat = new Models.Category();
cat.CategoryName = CategoryName;            

Ela já podia vir direto para o método, com as propriedades preenchidas, assim:

public ActionResult Save(Models.Category cat)

Porque não? Fica bem mais coerente. Até porque, se eu tiver uns 3 ou 4 métodos que trabalham com a categoria, não precisaria ficar alterando todos eles sempre que incluo ou excluo uma propriedade nova.

Isso já é possível no Preview 5, e funciona direitinho. Eles criaram um negócio chamado de Model Binders. A idéia é ligar valores que vêm de algum lugar (qualquer lugar), ao seu objeto de negócio. De onde vêm os valores que vão ser utilizados para compor o seu objeto de negócio é você quem decide. Vem de cookies, query string, sessão, você quem manda. Tudo funciona baseado em uma simples interface: IModelBinder. Vejam sua assinatura:

public interface IModelBinder
{
    object GetValue(ControllerContext controllerContext, string modelName, 
       Type modelType, ModelStateDictionary modelState);
}

Simples, não é? Como funciona?

Assim: você recebe um contexto do controlador, que contém tudo sobre o que está acontecendo, como informações de Request e do contexto HTTP (em forma de um System.Web.BaseHttpContextBase – do System.Web.Abstractions, e um BaseHttpRequestBase), e também do roteamento, como dados da rota, da ação sendo chamada, etc, etc. Tudo isso vem na variável controllerContext. Você tem também o nome da variável que vai ser ligada. No meu caso ela se chama “cat”:

public ActionResult Save(Models.Category cat)

Na variável modelType, você recebe os dados do tipo que deve ser criado, nesse caso, uma Category. E na variável modelState uma coleção de dados de estado do modelo. Você junta isso tudo, aquece por meia hora, coloca uma pitada de sal, e no final sai um objeto:

public class CategoryBinder : IModelBinder
{ 
    #region IModelBinder Members
 
    public object GetValue(
        ControllerContext controllerContext, 
        string modelName, 
        Type modelType, 
        ModelStateDictionary modelState)
    {
        var cat = new Models.Category();
        HttpRequestBase request = controllerContext.HttpContext.Request;
        cat.CategoryName = request["CategoryName"];
        cat.Description = request["Description"];
        return cat;                
    }
 
    #endregion
}

Vejam que nesse caso eu ignorei praticamente tudo, só usei os dados do Request, que veio via controllerContext. Acho que essa vai ser a solução mais usada.

Além da interface há também uma classe DefaultBinder, mas não sei q