DEV Community

Cover image for Reutilizando o @model do Razor com VueJs
Marcelo Machado
Marcelo Machado

Posted on

1 1

Reutilizando o @model do Razor com VueJs

O problema

Para quem trabalha com .Net, é muito comum renderizar suas páginas server-side utilizando o Razor. E, por muito tempo, tivemos o jQuery como aliado quando se era necessário fazer alguma chamada AJAX ou manipular algum DOM. Esta era a stack padrão.

Com a adoção do VueJS, nossa vida melhorou muito. Porém, sempre que quisermos representar o objeto renderizado pelo Razor no projeto Vue, precisamos reescrever todo o objeto usando a sintaxe Js.

Neste post, pretendo mostra um pouco de como eu faço para que os objetos enviados do controller para a view estejam também disponíveis no código Vue de forma automática.

Vamos imaginar que tenhamos a seguinte estrutura:

Person.cs

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

PersonController.cs

public class PersonController : Controller
{
    public IActionResult Form()
        {
            var person = new Person();
            return View(person);
        }
}

Os inputs do formulário já fazem o bind com os atributos do objeto Vue que vamos criar mais adiante.

Form.cshtml

@model Person

<form asp-route="Save" method="post">
    <input asp-for="Id" v-model="Model.Id"  />
    <input asp-for="Name" v-model="Model.Name"  />
    <input asp-for="Age" v-model="Model.Age"  />
</form>

Para que possamos trabalhar com a classe Person no projeto Vue, e também para que o bind acima funcione, é necessário rescrever a classe inteira dentro do Vue:

main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  data() {
    return {
      Model: {
        Id: 0,
        Name: '',
        Age: 0
      }
    }
  },
  render: h => h(App),
}).$mount('#app')

Obviamente esta é uma abordagem bem simplista, mas ainda assim, seria necessário rescrever toda a classe Person de alguma forma, para poder ter acesso como no exemplo abaixo:

//...
methods: {
  changeName () {
    this.Model.Name = 'New Name'
  }
}
//...

Preparando as coisas

Precisamos trabalhar com 3 alterações para que as coisas funcionem de forma automática. Primeiro, criaremos um método que transporte o objeto a ser renderizado para um formato JSON. Aqui, vou assumir que você estará criando uma classe BaseController para poder utilizar este método em todos os seus controllers.

BaseController.cs

public class BaseController : Controller
{
    protected JsonSerializerSettings jsonSettings;

    public BaseController()
    {
        this.jsonSettings = new JsonSerializerSettings
        {
            Culture = new CultureInfo("pt-BR"),
            DateFormatString = "dd/MM/yyyy",
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            Formatting = Formatting.Indented
        };
    }

    public ViewResult ViewJson(object model, string view = "")
    {
        // Transformamos o objeto em Json e enviamos para a view usando ViewBags
        ViewBag.Model = JsonConvert.SerializeObject(model, this.jsonSettings);

        // Depois a view é renderizada normalmente
        if (string.IsNullOrWhiteSpace(view))
            return View(model);
        else
            return View(view, model);
    }
}

Agora com o objeto serializado, vamos adicioná-lo em uma variável JavaScript global chamada model. Esta variável será utilizada posteriormente em nosso projeto Vue.

Faremos isso no arquivo de Layout, uma vez que esta solução será usada por todo o sistema.

_Layout.cshtml

<html>
    <head>
        <script>
            @if (string.IsNullOrWhiteSpace(ViewBag.Model))
            {
                <text>const model = null;</text>
            }
            else
            {
                <text>const model = @Html.Raw(ViewBag.Model);</text>
            }
        </script>
    </head>
    ...
</html>

E por último, precisamos vamos tornar a variável global model acessível a partir do root do Vue.

Main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  data() {
    return {
      Model: model
    }
  },
  render: h => h(App),
}).$mount('#app')

// Sempre adiciono esta linha para deixar o Vue acessível pelo console do navegador
window.vue = vue;

Aplicando as modificações

Agora, basta alterar os controllers, trocando a chamada do método View() para ViewJson().

PersonController.cs

public class PersonController : Controller
{
    public IActionResult Form()
        {
            var person = new Person();
            //Única alteração necessária nos controllers
            return ViewJson(person);
        }
}

Conclusão

Agora, toda e qualquer action retornará além da página Razor renderizada em server-side, você também terá a sua disposição um objeto Vue representando a classe atribuída em @model.

Jetbrains image

Is Your CI/CD Server a Prime Target for Attack?

57% of organizations have suffered from a security incident related to DevOps toolchain exposures. It makes sense—CI/CD servers have access to source code, a highly valuable asset. Is yours secure? Check out nine practical tips to protect your CI/CD.

Learn more

Top comments (0)

AI Agent image

How to Build an AI Agent with Semantic Kernel (and More!)

Join Developer Advocate Luce Carter for a hands-on tutorial on building an AI-powered dinner recommendation agent. Discover how to integrate Microsoft Semantic Kernel, MongoDB Atlas, C#, and OpenAI for ingredient checks and smart restaurant suggestions.

Watch the video 📺

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, cherished by the supportive DEV Community. Coders of every background are encouraged to bring their perspectives and bolster our collective wisdom.

A sincere “thank you” often brightens someone’s day—share yours in the comments below!

On DEV, the act of sharing knowledge eases our journey and forges stronger community ties. Found value in this? A quick thank-you to the author can make a world of difference.

Okay