Skip to main content

Criando páginas de erro 404 personalizadas no ASP.NET MVC

É muito fácil de se criar páginas de erro personalizadas no MVC. Veja como fazer.

Posted in MVC, Dicas, ASP.NET

Todo mundo que trabalha fazendo sites sabe que ter páginas de erro é indispensável. Só que quando se trabalha com ASP.NET MVC é muito complicado se acertar na hora de configurar as páginas de erro. Sim, usar o web.config é o recomendado. Mas você tem certeza de que está funcionando?

Objetivo

O nosso objetivo aqui é aprender a fazer uma página personalizada de erro 404 e retornar o HTTP status code correspondente (404) sem alterar a url.

O que aprendemos sobre erros no começo

Normalmente, quando estamos iniciando no ASP.NET, aprendemos que temos que colocar a tag no web.config, configurar os parâmetros e esperar o erro aparecer. Veja o exemplo abaixo:

<customErrors mode="On">
	<error statusCode="404" path="erro404.html" />
customErrors>

Páginas 404 personalizadas

Normalmente quando uma página não existe o site retorna o erro 404, não importa se a página é estática (página html simples) ou dinâmica (página gerada pelo backend). No caso do exemplo acima o ASP.NET a gente está dizendo para o site para redirecionar para uma página amigável quando acontecer algum erro 404.

Até aí tudo bem.

O problema do MVC

No caso do MVC o buraco acaba sendo mais embaixo: Como o MVC é baseado em routes, controles e actions uma url como /lala/lele não vai passar pelo . O resultado vai ser aquele erro 404 padrão do ASP.NET.

A solução pra esse problema é simples, mas não é a mais correta. Basta colocar um redirect=”~/ erro404.html” no lugar do path, como no exemplo abaixo:

<customErrors mode="On">
	<error statusCode="404" redirect="~/erro404.html"/>
customErrors>

Agora, se você navegar pra uma url aleatória (lala/lele) você vai ser capaz de ver a sua página personalizada de erro. Só que, além da url se tornar /erro404.html?aspxerrorpath=/lala/lele você vai ver que o HTTP status code da página é 200.

E isso é muito longe do objetivo que traçamos no começo.

Não sou especialista em SEO mas deixa eu tentar explicar o problema: Se por um acaso a página que os indexadores acharem não existe, mas estamos retornando 200, eles vão achar que a página existe e vão indexar a página 404 personalizada como se ela fizesse parte da navegação do site.

A solução ideal

Como eu disse no começo, a ideia é retornar uma página de erro 404 personalizada junto com o HTTP status code correto, que é 404. E obviamente não podemos alterar a url. A maneira mais prática de se fazer isso é mexer direto no IIS. Claro que eu não vou tentar te convencer a ligar no seu host e pedir pra mudar alguma configuração. Para isso vamos usar o .

Simplificando: Enquanto o funciona no mesmo nível do ASP.NET, o funciona mais próximo ao IIS. O que significa que as alterações no vão afetar até mesmo arquivos estáticos. Logo, se quisermos fazer alguma alteração que seja mais próxima do servidor, é lá que devemos mexer.

Para fazer com que nossa página de erro 404 personalizada funcione no MVC devemos fazer como no exemplo a seguir:

<httpErrors errorMode="Custom">
	<remove statusCode="404"/>
	<error statusCode="404" path="/erro404.html" responseMode="File"/>
httpErrors>

Reparou que eu usei um antes? Isso evita erros caso já tenha algum statusCode=”404” definido. E, apesar de eu estar usando uma página html simples (o ideal), podemos usar uma rota específica para a página 404. Como por exemplo /erro/404. Só que nesse caso é recomendado usar o responseMode=”ExecuteUrl”.

Agora, se formos acessar uma url aleatória /lala/lele vamos ver que:

  1. A página 404 foi chamada
  2. O HTTP status code é 404
  3. A url não foi alterada

Pronto. Espero que isso tenha sanado suas dúvidas. De qualquer forma fique à vontade para comentar e perguntar.

Did you like the article?

You can subscribe and get them as soon they are online, share using the buttons bellow or leave a comment.

And you also can share using your favorite social network:

Upload de arquivos usando ASP.NET MVC, AJAX e jQuery

É muito fácil de fazer um uploader usando componentes do Bootstrap com barra de progresso

Posted in MVC, C#, Tutoriais, ASP.NET, AJAX

Eu resolvi pegar meu artigo e código antigos pra atualizar. Por exemplo: Enquanto antes eu tinha usado o Visual Studio 2010 pra desenvolver um projeto em MVC3 agora eu estou usando o Visual Studio 2012 pra criar um projeto em ASP.NET MVC4 usando bootstrap e uma versão mais recente de todos os plugins que eu usei antes.

Primeiro passo

Antes de mais nada a gente precisa criar um Model do mesmo jeito que Scott Hanselman criou em seu artigo. Assim temos o nome (Name), tamanho (Length) e tipo (Type) do arquivo que vamos enviar pro servidor:

public class UploadFilesResult
{
	public string Name { getset; }
	public int Length { getset; }
	public string Type { getset; }
}

Segundo passo

Agora nós precisamos de uma Action Method que vai efetivamente pegar o arquivo, tratar e salvar no servidor. Vamos chamar esta Action Method usando o método http POST, pegar a lista de arquivos selecionados e salvar dentro de App_Data. Esta Action Method vai retornar uma string em formato json com o Name, Length and Type dos arquivos:

[HttpPost]
public ContentResult UploadFiles()
{
	var r = new List<ViewDataUploadFilesResult>();
 
	foreach (string file in Request.Files)
	{
		HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;
		if (hpf.ContentLength == 0)
			continue;
 
		string savedFileName = Path.Combine(Server.MapPath("~/App_Data"), Path.GetFileName(hpf.FileName));
		hpf.SaveAs(savedFileName); // Save the file
 
		r.Add(new ViewDataUploadFilesResult()
		{
			Name = hpf.FileName,
			Length = hpf.ContentLength,
			Type = hpf.ContentType
		});
	}
	// Returns json
	return Content("{\"name\":\"" + r[0].Name + "\",\"type\":\"" + r[0].Type + "\",\"size\":\"" + string.Format("{0} bytes", r[0].Length) + "\"}""application/json");
}

Terceiro passo

Agora precisamos usar um plugin do jQuery chamado jQuery File Upload. Ele já traz nativamente um monte de coisa bacana mas, para simplificar, vamos usar apenas 2 arquivos (além de outros que já estou usando): jquery.fileupload.css and jquery.fileupload.js.

Quarto passo

Com isso a gente precisa de alguma maneira de enviar os arquivos. Isso é o que eu criei - apenas para o upload - mas você pode adaptar para seu projeto:

<div class="container">
	<span class="btn btn-success fileinput-button">
		<i class="glyphicon glyphicon-plus">i>
		<span>Add files...span>
		<input id="fileupload" type="file" name="files[]" multiple>
	span>
	<br />
	<div class="progress">
		<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width0%;">
			<span class="sr-only">0% completespan>
		div>
	div>
	<br />
	<div class="file_name">div>
	<br />
	<div class="file_type">div>
	<br />
	<div class="file_size">div>
div>

Observe 4 coisas:

  1. Eu não usei nenhum HtmlHelper para criar o form. O motivo disso é a facilidade de se criar um form sem HtmlHelper, sem contar que não precisamos usar os HtmlHelpers o tempo todo;
  2. Eu não estou usando form tag. O plugin toma conta de tudo o que precisamos;
  3. A barra de progresso graças ao bootstrap;
  4. As divs no final. Elas só estão lá pra receber e mostrar o que o json trouxe..

Último passo

Depois de organizarmos é hora de fazer o javascript pra fazer isso tudo funcionar. Eu estou usando o plugin jQuery File Upload chamando a Action method UploadFiles criado no HomeController. Some isso ao evento que coloquei no javascript mostrando o status do upload usando a barra de progresso do bootstrap:

<script type="text/javascript">
	$(document).ready(function () {
		$('#fileupload').fileupload({
			dataType: 'json',
			url: '/Home/UploadFiles',
			autoUpload: true,
			done: function (e, data) {
				$('.file_name').html(data.result.name);
				$('.file_type').html(data.result.type);
				$('.file_size').html(data.result.size);
			}
		}).on('fileuploadprogressall'function (e, data) {
			var progress = parseInt(data.loaded / data.total * 100, 10);
			$('.progress .progress-bar').css('width', progress + '%');
		});
	});
script>

É isso. Agora você está pronto pra colocar esse recurso no seu site. E sem postback!

Você pode baixar o código aqui: jQueryFileUploadMVC4.zip (5.84 MB). Sim, quase 6MB, graças aos packages do NuGet.

Did you like the article?

You can subscribe and get them as soon they are online, share using the buttons bellow or leave a comment.

And you also can share using your favorite social network: