ASP.NET MVC: Criando um tipo personalizado de Action Result

Blz, pessoal

Falei no post anterior de MVC sobre as action results como objetos responsáveis pela resposta ao navegador, seja como uma página html, um arquivo pdf, um redirecionamento para outra action, etc.

Embora os tipos built-in de action result atendam a maioria dos casos, é possível implementar sua própria action result, derivando de uma das action results existentes ou ainda da classe abstrata ActionResult diretamente.

Vou mostrar neste post um exemplo disso: retornar uma imagem com marca d’água. Este exemplo foi retirado do ótimo livro Pro ASP.NET MVC 2 Framework.

A implementação é bem simples. Como dito antes, tudo que temos que fazer é herdar de uma action result existente ou da classe base ActionResult. Neste exemplo, a classe responsável pela geração da imagem com marca d’água herdará diretamente de ActionResult.

Vamos no passo-a-passo.

1) Em um projeto ASP.NET MVC 3, crie uma classe chamada ImagemComMarcaDAguaResult, herdando de ActionResult, como abaixo:

public class ImagemComMarcaDAguaResult : ActionResult
{
}

2) Ao herdar de ActionResult, o único método que precisa ser sobrescrito é ExecuteResult. Nele estará toda a lógica responsável por retornar o seu result personalizado. O “esqueleto” da classe fica assim:

public class ImagemComMarcaDAguaResult : ActionResult
{
    public override void ExecuteResult(ControllerContext context)
    {
    }
}

3) Antes de irmos para a implementação de ExecuteResult, criamos 2 propriedades na classe: uma com o nome da imagem na qual será inserida a marca d’água e outra com o texto da marca d’água (como “tarefa para o lar”, vocês podem inserir uma imagem como marca d’água). Essas 2 propriedades serão inicializadas via construtor:

public class ImagemComMarcaDAguaResult : ActionResult
{
    public string NomeDoArquivoDeImagem { get; private set; }
    public string TextoDaMarcaDAgua { get; private set; }

    public ImagemComMarcaDAguaResult(string nomeDoArquivoDeImagem, string textoDaMarcaDAgua)
    {
        NomeDoArquivoDeImagem = nomeDoArquivoDeImagem;
        TextoDaMarcaDAgua = textoDaMarcaDAgua;
    }

    public override void ExecuteResult(ControllerContext context)
    {
    }
}

4) Agora vamos à implementação de ExecuteResult (explicação nos próprios comentários do código):


public override void ExecuteResult(ControllerContext context)
{
    // obtemos:
    // um objeto Image a partir do nome do arquivo fornecido no construtor
    // um objeto Graphics para manipularmos a imagem
    // um objeto Font (obvio)
    // um MemoryStream para salvarmos a imagem alterada em memoria
    using (var imagem = Image.FromFile(NomeDoArquivoDeImagem))
    using (var grafico = Graphics.FromImage(imagem))
    using (var fonte = new Font("Arial", 12, FontStyle.Bold|FontStyle.Italic))
    using (var memoryStream = new MemoryStream())
    {
        // medimos o tamanho do texto da marca d'agua para desenharmos no limite correto da imagem
        var tamanhoDoTexto = grafico.MeasureString(TextoDaMarcaDAgua, fonte);

        // desenhamos o texto na imagem, passando fonte, cor e posicao (x e y)
        grafico.DrawString(TextoDaMarcaDAgua, fonte, Brushes.DarkRed, 10, imagem.Height - tamanhoDoTexto.Height - 10);

        // salvamos a imagem alterada em memoria
        imagem.Save(memoryStream, ImageFormat.Png);

        // retornamos a imagem em formato png
        var response = context.RequestContext.HttpContext.Response;
        response.ContentType = "image/png";
        response.BinaryWrite(memoryStream.GetBuffer());
    }
}

5) Agora que temos nossa action result prontinha, é hora de colocá-la em funcionamento. Para isso, criamos um controller com a action ExibirImagem, a qual retorna um ImagemComMarcaDAguaResult. Abaixo, código completo do controller:

public class MarcaDAguaController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ImagemComMarcaDAguaResult ExibirImagem(string nomeDoArquivoDeImagem)
    {
        // obtemos o caminho completo do arquivo
        var pastaDeImagens = Server.MapPath("~/content/images");
        var caminhoCompleto = Path.Combine(pastaDeImagens, Path.GetFileName(nomeDoArquivoDeImagem));

        // definimos o texto da marca d'água
        var textoDaMarcaDAgua = "Hora atual: " + DateTime.Now.ToShortTimeString();

        // retornamos a imagem com marca d'água
        return new ImagemComMarcaDAguaResult(caminhoCompleto, textoDaMarcaDAgua);
    }
}

6) Por fim, criamos a view Index (clique com o botão direito na action Index do controller e Add View…)  para exibir a imagem. Para isso, a view só precisa de uma única linha:

<img src="@Url.Action("ExibirImagem", "MarcaDAgua", new { nomeDoArquivoDeImagem = "teste.jpg" })" />

Notem que chamamos a action ExibirImagem do controller MarcaDAgua, passando como parâmetro a imagem de nome “teste.jpg”. Vale lembrar que, para o exemplo funcionar, esta imagem deverá estar dentro da pasta “~/Content/Images”, conforme definido na action ExibirImagem.

7) Agora, basta rodar a aplicação e acessar  o endereço http://localhost:%5Bporta%5D/MarcaDagua e sua imagem “teste.jpg” será exibida no navegador com a marca d’água (no caso do exemplo, com a hora atual). Veja como fica:

Imagem com hora atual de marca d'água

Pronto! Concluímos nossa action result customizada. Básico, não é?

Claro que se trata de um exemplo didático. Em um projeto real, algumas coisas no código poderiam ser mais genéricas (como a fonte usada na marca d’água) e a pasta de obtenção das imagens não deveria estar “hard-coded” na action ExibirImagem.

Espero que tenham gostado. Sugestões, críticas…só comentar.

That’s all, folks!

Anúncios

Participe! Vamos trocar uma ideia sobre desenvolvimento de software!

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s