Criando componente reutilizável com JavaScriptResult do .Net MVC

Hoje aprendi: Como utilizar o JavaScriptResult do .Net MVC para entregar javascript no formato de componente

O JavaScriptResult, bem como o ActionResult, são formas de retornar informações através de uma action em um Controller no .Net MVC. Utilizei algumas vezes para algumas aplicações pontuais, até que fui questionado sobre como embedar um código criado por mim, dentro do site de um cliente. Bom, nesse ponto o problema não era como fazer, mas sim, qual a melhor forma dentro do cenário que proposto.

O que eu sabia:

  1. Poderia entregar JavaScript com o JavaScriptResult.
  2. Um componente possui código HTML.
  3. Um componente pode querer se comunicar com uma determinada API e entregar também esses dados "embedados".
  4. Lógicas de negócio necessitariam de resoluções do meu componente.
  5. O cliente precisaria passar parâmetros para meu componente.



Criei uma View que possui todo o código HTML (no _ViewStart removi meu layout, não quero injetar as tags <html><body><head> pois a aplicação cliente já possui) que quero entregar para a aplicação cliente, e no meu controller, duas Actions, uma que retorna minha View (apenas para testar, pois eu pego o html da view diretamente da view que retorna javascript) e outra que retorna um código JavaScript.

A view que retorna JavaScriptResult precisa formatar o html de modo que ele possa ser injetado, como javascript, em uma pagina HTML do cliente. Para isso, criei um método que vai encontrar no HTML cliente a posição onde o meu script foi adicionado. Então, eu coloco o script  que faz a busca pela posição, concatenado com o HTML do meu componente já formatado como string javascript para que seja renderizado corretamente no cliente.

Para fazer a injeção do HTML, usei a função abaixo:


private string Html2Js(string html) {

            return @"

                var scripts = document.getElementsByTagName('script');

                var item;

                for(var i = 0; i < scripts.length; i++)

                {
                    if(scripts[i].src.toLowerCase().indexOf('/boasvindas/ola') > 0)
                        item = scripts[i];
                }
                item.parentElement.insertAdjacentHTML('beforeend', '" + html.Replace("'","\"").Replace(Environment.NewLine, string.Empty) + @"');
            ";
        }

Ah, claro, não posso esquecer de comentar que precisei pegar o html da View e para isso, usei a outra função abaixo:

private string View2String(string vn, object m)
        {
            ViewData.Model = m;
            using (var sw = new StringWriter())
            {
                var result = ViewEngines.Engines.FindPartialView(ControllerContext, vn);
                var viewContext = new ViewContext(ControllerContext, result.View, ViewData, TempData, sw);
                result.View.Render(viewContext, sw);
                result.ViewEngine.ReleaseView(ControllerContext, result.View);

                return sw.GetStringBuilder().ToString();
            }
        }

A controller fica mais ou menos assim:













Claro que é valido retirar da controller e colocar em uma classe a parte as funções Html2Js e View2String.

E para testar esse componente, basta criar um arquivo HTML (simulando um cliente) com o conteúdo:

















<html>
   <head></head>
   <body>
      <h1> Vou carregar o componente logo abaixo: </h1>
      <div>
         <script src="http://localhost:54516/BoasVindas/ola/6"></script>
      </div>
   </body>
</html>


* localhost:54516 é a porta gerado pelo IIS Express.

O Código completo da solução está disponível em: https://github.com/rcelebrone/Componente-JavaScriptResult