Sorry, this entry is only available in Português.
Globalizing jQuery validation with ASP.NET MVC 3
ASP.NET MVC 3 has a great feature which is client validation using jQuery plugin’s jQuery validations and using a Microsoft script the validation is made without the need of any other special code. You just have to use the attributes from System.ComponentModel.DataAnnotations namespace.
For those who don’t know, to use this validation you just need to add the following script references (which are included in the default template when a new Asp.Net Mvc 3 gets created):
<script src=”/Scripts/jquery-1.6.2.min.js” type=”text/javascript”></script>
<script src=”/Scripts/jquery.validate.min.js” type=”text/javascript”></script>
<script src=”/Scripts/jquery.validate.unobtrusive.min.js” type=”text/javascript”></script>
Pretty simple actually! But there is an issue, this script is not globalized. So, let’s say you have an attribute inside your class of the DateTime type and you’d like to validate it, for instance, I had a class which among other things had a DateTime. Just to make things simples, it was something like this:
1 2 3 4 5 6 7 8 9 10 11 12 | public class Person { public string Name { get; set; } public string Sex { get; set; } public string Rg { get; set; } [DataType(DataType.EmailAddress)] public string Email { get; set; } [DataType(DataType.Date)] public DateTime? BirthDate { get; set; } } |
So when a filled a form with the date 16/09/1980, for instance, automatically it was detected as an invalid date, since the expected is a date using the pattern mm/dd/yyyy, but of course, here in Brazil the pattern is different, it is dd/mm/yyyy.
So how can I fix it?
First of all, I have to use the jQuery’s plugin Globalize. I just have to add references to two scripts.
<script type=”text/javascript” src=”@Url.Content(“~/Scripts/globalize.js”)”></script>
<script type=”text/javascript” src=”@Url.Content(“~/Scripts/cultures/globalize.culture.pt-BR.js”)”></script>
After that, all it has to be done is set the desired culture and write a small function to parse the date using the Globalize parseDate function:
1 2 3 4 | Globalize.culture("pt-BR"); $.validator.methods.date = function(value, element) { return this.optional(element) || Globalize.parseDate(value); }; |
It couldn’t be more simple!
Localização de mensagem de erro no ASP.NET MVC
Sabe quando você preenche uma data inválida em uma página usando o ASP.NET MVC e o erro vem em inglês assim:
Isso acontece porque o DefaultModelBinder do MVC não conseguiu converter essa data, no caso acima, é óbvio porque não existe um mês 15. A questão é, como traduzir essa mensagem?
Um jeito que achei foi adicionando uma pasta App_GlobalResources e dentro dessa pasta adicionar um arquivo de resources, que no caso, chamei de CustomMvcResources.resx.
Nesse arquivo de resources adicione a seguinte linha:
No global.asax altere o método Application_Start para que fique assim:
1 2 3 4 5 6 | protected void Application_Start() { AreaRegistration.RegisterAllAreas(); DefaultModelBinder.ResourceClassKey = "CustomMvcResources"; RegisterRoutes(RouteTable.Routes); } |
O importante é que o valor informado à propriedade ResourceClassKey tenha o nome do arquivo de resource criado.
Agora o erro será apresentado do jeito que foi configurado no arquivo de resources.
ASP.NET MVC e o Grid do MvcContrib
Uma das coisas que eu sempre gostei do ASP.NET Web Forms era a produtividade que a gente ganhava com os controles, entre eles, um dos que eu mais usava sempre foi o GridView. E devo admitir que esse foi também um fator de resistência para eu começar a usar o ASP.NET MVC.
Resistência vencida, toda a vez que eu precisava de um Grid, ou seja, de dados tabulares, eu usava o bom e velho e um loop através dos meus objetos da collection.
Isso é claro, até eu me aventurar com o Grid do MvcContrib. O MvcContrib é um projeto open source que, entre outras coisas, possui esse Grid que é muito prático e simples.
Pra começar é só baixar o assembly do site do projeto e adicionar uma referência para o assembly MvcContrib.dll
Eu fiz uma action bem simples que retorna uns dados estáticos para a página:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public ViewResult Index() { var produtos = new List { new Produto { Id = 1, Nome = "Chaveiro", Valor = 11.50m, Categoria = new Categoria {Id = 1, Nome = "Utilitários"} }, new Produto { Id = 2, Nome = "Mouse", Valor = 100m, Categoria = new Categoria {Id = 2, Nome = "Informática"} }, new Produto { Id = 3, Nome = "Pen-Drive 8GB", Valor = 150.99m, Categoria = new Categoria {Id = 2, Nome = "Informática"} } }; return View(produtos); } |
E na view é muito simples também:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <%@ Import Namespace="MvcContrib.UI.Grid" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Lista de Produtos </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Lista de Produtosh2> <%= Html.Grid(Model).Columns(coluna => { coluna.For(x => x.Nome); coluna.For(x => x.Valor); coluna.For(x => x.Categoria.Nome); }) %> </asp:Content> |
Isso gera um grid simples na página:
Agora vamos permitir uma ordenação, primeiro eu altero a view para exibir os links de ordenação:
1 2 3 4 5 6 7 8 9 | <%= Html.Grid(Model) .Sort(ViewData["sort"] as GridSortOptions) .Columns(coluna => { coluna.For(x => x.Nome); coluna.For(x => x.Valor); coluna.For(x => x.Categoria.Nome).Named("Categoria"); }) %> |
E na action do controller eu faço seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 | using MvcContrib.Sorting; // ... public ViewResult Index(GridSortOptions sort) { var produtos = GetProdutos(); if (sort.Column == null) sort.Column = "Nome"; produtos = produtos.OrderBy(sort.Column, sort.Direction); ViewData["sort"] = sort; return View(produtos); } |
Para ficar mais claro eu movi a inicialização dos produtos para um outro método. Mas como você pode ver no código acima, é muito simples adicionar ordenação.
Por fim, para paginar alteramos a action:
1 2 3 4 5 6 7 8 9 10 11 12 13 | using MvcContrib.Pagination; // ... public ViewResult Index(GridSortOptions sort, int? pagina) { var produtos = GetProdutos(); if (sort.Column == null) sort.Column = "Nome"; produtos = produtos.OrderBy(sort.Column, sort.Direction); ViewData["sort"] = sort; return View(produtos.AsPagination(pagina ?? 1, 10)); } |
E na view usamos um helper para exibir as páginas:
1 2 3 4 5 6 7 8 9 10 11 | <%= Html.Grid(Model) .Sort(ViewData["sort"] as GridSortOptions) .Columns(coluna => { coluna.For(x => x.Nome); coluna.For(x => x.Valor); coluna.For(x => x.Categoria.Nome).Named("Categoria"); }) %> <%= Html.Pager((IPagination)Model).Format("Exibindo {0} - {1} de {2}") %> |
Conclusão
Fazer paginação e ordenação manualmente em grids pode ser bem complicado às vezes. Pela simplicidade da solução hoje o Grid do MvcContrib é a minha primeira opção.
Publicando um site em ASP.NET MVC no IIS 6
Publicar um site feito usando o ASP.NET MVC no servidor IIS não é tão simples como apenas copiar os arquivos, algumas configurações são necessárias:
1) Dentro do IIS abra as propriedades no seu site e na aba Home Directory, clique no botão Configuration. Dentro de Application Extensions, selecione a extensão .aspx e clique em Edit. Copie o conteúdo da caixa Executable como na figura abaixo e clique em Cancel.
2) Clique no botão INSERT e cole o texto na caixa Executable e desmarque a opção Verify that file exists como na figura abaixo.
3) Por último temos que “adicionar uma extensão” para as urls já que o IIS 6 exite que exista uma extensão. O jeito mais fácil de fazer é isso dentro do Global.asax.cs. Altere a rota padrão e suas outras rotas para que fiquem assim:
1 2 3 4 5 6 | public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute("Default", "{controller}.mvc/{action}/{id}", new {action = "Index", id = ""}); } |
Veja que depois do controller adicionei a extensão .mvc, agora todas as rotas funcionarão com o caminho /controler.mvc/action. É importante que para isso não existam urls fixas em suas páginas, apenas urls criadas usando os html helpers.
CodeTemplates com ASP.NET MVC
Toda a vez que você vai adicionar uma View usando o assistente do Visual Studio

Uma nova página é adiciona com um código pré-definido e baseado na opção que você escolheu em “View Content”, o que muita gente não sabe é que dá para customizar todos esses modelos de página e é muito simples fazer isso.
Adicionando os arquivos ao projeto
Primeiro vá em C:Program FilesMicrosoft Visual Studio 9.0Common7IDEItemTemplatesCSharpWeb
Obs.: Veja que esse caminho vai variar de acordo com sua instalação e com a linguagem escolhida.
Se você tiver o ASP.NET MVC 1 e 2 instalados você deve encontrar duas pastas ali dentro chamadas respectivamente MVC e MVC2. Entre na pasta da versão escolhida copie a pasta CodeTemplates e cole na raíz do seu projeto web. Você deve acabar com um projeto assim:

O Visual Studio sempre vai procurar por esses arquivos localmente no projeto e se não encontrar buscará os arquivos na pasta informada acima.
Configurando os arquivos
Você já deve ter percebido não é? Existe um arquivo para cada template. Todas com uma extensão .tt que é a extensão do T4 (Text Template Transformation Toolkit).
O T4 é uma ferramenta de geração de código baseada em templates que vem nativa junto com o Visual Studio desde a versão 2005. Aliás, vale para o T4 um investimento de estudos já que é uma ferramenta muito útil.
A primeira coisa que precisa ser feita é selecionar todos os arquivos .tt ir na janela de propriedades e limpar o campo Custom Tool. Deixe em branco.

Alterando um template
Agora vamos realmente alterar um template. Vamos supor que eu queira, ao exibir o detalhe de uma classe que ela fosse exibida dentro de uma tabela. Originalmente, as propriedades são exibidas em divs ao invés de tabelas (que na minha opinião, é a melhor opção).
Veja como ficou o arquivo Details.tt

Outra modificação que eu fiz na modelo de Details, foi, ao invés de exibir o título dentro de uma tag h2, eu exibo dentro da tag h1.

Pronto! Agora toda vez que for adiciona uma View com base no modelo Details ele seguirá esse padrão.
Uma outra coisa que pode ser feita é salvar um novo modelo dentro daquela pasta com outro nome, por exemplo, eu fiz essas alterações e salvei o arquivo como DetailsVintem.tt. Agora quando eu tento adicionar uma View essa opção fica disponível para mim.

Postando um objeto JSON para uma Action MVC2 com jQuery
Há um tempo atrás eu postei uma versão desse artigo utilizando o Asp.Net MVC1.Agora, o MVC2 está no ar e com isso ficou mais fácil postar um objeto Json para uma action.
Para começar, baixe o ASP.NET MVC2 Futures e adicione uma referência no seu projeto para Microsoft.Web.Mvc.dll e no Global.asax.cs registre a chamada para o provedor do json, dessa forma:
1 2 3 4 5 6 | protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); ValueProviderFactories.Factories.Add(new JsonValueProviderFactory()); } |
Do lado do Asp.Net é só isso. Faça sua Action normalmente esperando um objeto, no meu caso eu segui o exemplo anterior com o caso do cliente:
Fiz uma classe Cliente
1 2 3 4 5 | public class Cliente { public string Nome { get; set; } public string Cnpj { get; set; } } |
E minha action ficou assim:
1 2 3 4 | public JsonResult Criar(Cliente cliente) { return Json(cliente); } |
Obviamente, essa não é uma action muito criativa, simplesmente está recebendo um objeto da classe Cliente e retornando como Json, mas aqui poderia ser feito qualquer coisa, não é necessário retornar um objeto json.
Por fim, para enviar um objeto json pelo jquery precisamos de um plugin, já que o jquery não faz isso nativamente. Eu usei o jquery-json, que tem um método toJSON para converter um objeto javascript para json.
Veja como ficou meu script:
Mas uma vez, um script sem muito segredo, estou pegando os valores de caixas de texto e montando meu objeto, depois convertendo a variável cliente para um objeto json armazenado na variável encoded e passando essa variável na chamada ajax para a action.
Nova sintaxe para fazer Html Encoding com Asp.Net 4 e Asp.Net MVC 2
Html Encoding faz parte de todo desenvolvimento web, principalmente para previnir ataques de Cross Site Scripting (XSS) – quem não sabe o que é, recomendo ler esse artigo.
Até a versão 3.5 no Asp.Net para fazer Html Enconding tinhamos que fazer algo assim:
1 | <%= Server.HtmlEncode(algum_valor) %> |
E no Asp.Net MVC algo assim:
1 | <%= Html.Encode(model.Valor) %> |
Isso sempre funcionou, mas agora existe uma nova possibilidade, que na minha opinião torna isso ainda mais simples:
1 | <%: mode.Valor %> |
É só trocar o sinal de = pelo sinal : e automaticamente o encoding será realizado.
E isso vale também para os outros Html helpers do MVC, por exemplo:
1 | <%: Html.TexboxFor(m => m.Valor) %> |
No código acima, o texto dentro do textbox já sairá codificado.
Customizando Templates no Asp.Net MVC2
Customizar os templates padrão do Asp.Net MVC2 é muito fácil. Já mostrei antes como usar os templates, agora vou mostrar como customizar.
A primeira coisa que é preciso saber para customizar é que quando o MVC2 busca por customizações ele busca nas seguintes pastas:
- ~/Areas/NomeDaArea/Views/NomeDoController/DisplayTemplates/TemplateName.aspx & .ascx
- ~/Areas/NomeDaArea/Views/Shared/DisplayTemplates/TemplateName.aspx & .ascx
- ~/Views/NomeDoController/DisplayTemplates/TemplateName.aspx & .ascx
- ~/Views/Shared/DisplayTemplates/TemplateName.aspx & .ascx
- ~/Areas/NomeDaArea/Views/NomeDoController/EditTemplates/TemplateName.aspx & .ascx
- ~/Areas/NomeDaArea/Views/Shared/EditTemplates/TemplateName.aspx & .ascx
- ~/Views/NomeDoController/EditTemplates/TemplateName.aspx & .ascx
- ~/Views/Shared/EditTemplates/TemplateName.aspx & .ascx
Veja que são principalmente duas pastas DisplayTemplates para os templates de exibição e EditTemplates para os de edição dispostas em alguns locais específicos.
Só para facilitar vou continuar o exemplo feito no post anterior que tinha as views Index.aspx e Edit.aspx e classe de model Cliente.cs como mostrados abaixo:
![]()
![]()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class Cliente { public string Nome { get; set; } public string Email { get; set; } public bool Ativo { get; set; } [DisplayName("Data de Nascimento")] public DateTime DataNascimento { get; set; } public decimal Credito { get; set; } public static Cliente Criar() { return new Cliente { Nome = "Thiago Temple", Ativo = true, Credito = 1000, DataNascimento = new DateTime(1981, 10, 15) }; } } |
Existem alguns templates pré-definidos no MVC2, são eles: String, Html, Boolean, Decimal, EmailAddress, HiddenInput, Html, Object, String, Text, Url e DateTime. Então para se customizar um desses campos tudo o que temos que fazer é criar um arquivo com o nome do template na pasta específica. Vamos imaginar que a idéia fosse que toda que vez que tivéssemos uma propriedade do tipo DateTime e ela fosse editável nós gostaríamos que o textbox fosse exibido com uma classe css específica e ao lado do campo aparecesse uma imagem para que o usuário pudesse clicar e selecionar a data de um calendário em javascript, por exemplo.
Temos então que criar um arquivo DateTime.ascx na pasta ~/Views/Shared/EditTemplates/ assim esse template estará disponível para todas as propriedades DateTime do nosso projeto. Veja como ficaria esse arquivo:
![]()
Isso vale para todos os tipos de templates pré-definidos. Seguindo o exemplo do post passado, se quisermos modificar a exibição da nossa classe cliente para que ela fique dentro de uma tabela, veja como ficará o template do arquivo ~/Views/Shared/DisplayTemplates/Object.ascx
![]()
Dentro do objeto ViewData agora temos um objeto ModelMetadata que contém informações sobre a classe do Model que está sendo usada na view. Entre outras informações o que temos ali é uma coleção com todas as propriedades do model.
No exemplo acima primeiro exibimos o nome do model e depois fazemos um loop entre as propriedades do model exibindo as que estão marcadas com a opção ShowForDisplay = true, que é o padrão. Isso deve gerar uma página assim:
![]()
Para o template de edit não é muito diferente, veja o arquivo ~/Views/Shared/EditTemplates/Object.ascx:
![]()
Da mesma forma fazemos um loop nas propriedades do objeto ModelMetada que estão marcados com a propriedade ShowForEdit = true, novamente, esse é o padrão. Além disso, verifiquei se a propriedade é obrigatória e coloquei um * na frente do label. Veja o resultado:
![]()
Veja também que a modificação feita para o campo DateTime continuou valendo para a propriedade Data de Nascimento que foi exibida com a imagem do calendário ao lado do campo.
Conclusão
Os templates do MVC2 são uma forma simples e prática de exibir dados. Mas, o mais importante, são também muito poderosos para que sejam customizados da melhor forma possível para as necessidades específicas de cada projeto.
Validação com Asp.Net MVC2 parte 3 – Input vs Model validation
Obs.: Esse post está baseado na versão RC2 do Asp.Net MVC2.
O Asp.Net MVC 1 já possuía uma forma de realizar validações, como as validações Required ou Regular Expression que eu já mostrei aqui em outros posts, além dessa validação o framework também avisaria/perceberia erros ao submeter um formulário com dados inválidos, exemplo: enviar uma string com “xxxxx” para uma propriedade de data ou não enviar um valor para um campo que não fosse nullable, como, por exemplo, um campo int.
Vamos olhar uma classe de modelo como a classe Cliente abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class Cliente { public int IdCliente { get; set; } [Required(ErrorMessage = "Preencha o nome")] public string Nome { get; set; } [Required(ErrorMessage = "Preencha a idade")] [Range(0, 150, ErrorMessage="Idade inválida")] public int? Idade { get; set; } [Required(ErrorMessage = "Preencha o email")] [RegularExpression(@"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,4}$", ErrorMessage = "Email inválido")] public string Email { get; set; } [Required(ErrorMessage="Preencha o Cpf")] public string Cpf { get; set; } } |
E um formuário como o abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <%: Html.ValidationSummary() %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(model => model.Nome) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Nome) %> <%: Html.ValidationMessageFor(model => model.Nome) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.Idade) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Idade) %> <%: Html.ValidationMessageFor(model => model.Idade) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.Email) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Email) %> <%: Html.ValidationMessageFor(model => model.Email) %> </div> <p> <input type="submit" value="Create" /> </p> </fieldset> |
Repare que o modelo tem uma propriedade Cpf decorada com o atributo Required e no formulário essa propriedade não existe. No MVC1 ou até o RC1 do MVC2, se submetêssemos esse formulário, o campo Cpf não seria exigido. Isso é o que é conhecido como Input validation, ou seja, apenas os dados que são submetidos pelo formulário são validados. A partir do MVC RC2, esse campo também é validado, e isso é conhecido como Model validation.
Vou alterar a classe Cliente para ter um Endereco, como abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class Cliente { public int IdCliente { get; set; } [Required(ErrorMessage = "Preencha o nome")] public string Nome { get; set; } [Required(ErrorMessage = "Preencha a idade")] [Range(0, 150, ErrorMessage="Idade inválida")] public int? Idade { get; set; } [Required(ErrorMessage = "Preencha o email")] [RegularExpression(@"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,4}$", ErrorMessage = "Email inválido")] public string Email { get; set; } [Required(ErrorMessage="Preencha o Cpf")] public string Cpf { get; set; } public Endereco Endereco { get; set; } } public class Endereco { [Required] public string Logradouro { get; set; } [Required] public string Cidade { get; set; } [Required] public string Bairro { get; set; } } |
Veja que a propriedade Endereco não é obrigatória na classe Cliente. O que isso quer dizer? Que no Model Validation, se eu não informar nenhum atributo da classe Endereco, o endereço pode ser nulo.
Se eu mantiver o formulário como estava e não adicionar nenhuma outra caixa de texto ao enviar o formulário ele não vai validar o endereço. Agora vou alterar o formulário para que ele tenha o Cpf e a Cidade do Cliente. Assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <%= Html.ValidationSummary()%> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%= Html.LabelFor(model => model.Nome)%> </div> <div class="editor-field"> <%= Html.TextBoxFor(model => model.Nome)%> <%= Html.ValidationMessageFor(model => model.Nome)%> </div> <div class="editor-label"> <%= Html.LabelFor(model => model.Idade)%> </div> <div class="editor-field"> <%= Html.TextBoxFor(model => model.Idade)%> <%= Html.ValidationMessageFor(model => model.Idade)%> </div> <div class="editor-label"> <%= Html.LabelFor(model => model.Email)%> </div> <div class="editor-field"> <%= Html.TextBoxFor(model => model.Email)%> <%= Html.ValidationMessageFor(model => model.Email)%> </div> <div class="editor-label"> <%= Html.LabelFor(model => model.Cpf)%> </div> <div class="editor-field"> <%= Html.TextBoxFor(model => model.Cpf)%> <%= Html.ValidationMessageFor(model => model.Cpf)%> </div> <div class="editor-label"> <%= Html.LabelFor(model => model.Endereco.Cidade)%> </div> <div class="editor-field"> <%= Html.TextBoxFor(model => model.Endereco.Cidade)%> <%= Html.ValidationMessageFor(model => model.Endereco.Cidade)%> </div> <p> <input value="Create" type="submit" /> </p> </fieldset> |
Apenas o campo Cidade foi adicionada, mas ao submeter o formulário as propriedades Logradouro e Bairro também são validados.
Ou seja, agora a validação é feita sempre no Model e não mais de acordo com os dados que são informados.
Por que isso é importante? Principalmente porque alguém mal intensionado poderia tentar enviar um request de post com apenas parte dos dados. Nas versões anteriores do MVC isso não seria validado automaticamente.
Um ponto importante a se considerar são os atributos que não podem ser nulos como no caso do Int. Imagine que na nossa classe Cliente a propriedade Idade não fosse decorada com o atributo Required. Nas versões anteriores do MVC se o campo Idade não fosse preenchido um erro “A value is required” seria retornado, isso acontece no momento do model-binding, quando framework tenta identificar se existe um valor submetido para uma propriedade, no caso idade, que por padrão não pode ser nula.
A partir do MVC RC2 essa propriedade seria preenchida com o seu valor padrão, que no caso do int é 0.