10
respostas

Dúvida básica não respondida

Ótimo curso, mas fiquei com a seguinte dúvida:

Enquanto usávamos o método que retornava uma Task e recebia um HttpContext conseguíamos pegar qualquer informação do formulário através da propriedade contexto.Request.Form["propriedade"] , porém ao substituir pelos métodos do framework, não temos mais o HttpContext, e não foi explicado como pegar o valor de um campo no formulário. Só foi dito que o framework vai se virar pra entregar um objeto que for setado como parâmetro na assinatura do método de destino do formulário (Model Binding).

Como posso conseguir recuperar uma informação de um campo no formulário uma vez que não tenho mais o HttpContext sem o Model Binding?

10 respostas

Olá Rafael,

a ideia de usar o framework mvc é realmente tentar evitar o uso direto do HttpContext, deixar que ele cuide dessa parte de lidar com coisas como request e response para você por de baixo dos panos enquanto que no seu código você escreve coisas relacionadas com regra de negócio e orientação a objetos.

Por exemplo, vamos supor que estamos fazendo a tela de edição do livro. Então basicamente na request estão vindo 3 parâmetros, o id, titulo e o autor. Se eu receber o livro direto como parâmetro, neste caso ai vai ocorrer o model binding em que as propriedades serão preenchidas de acordo com os names enviados na requisição. Basta chamar as propriedades para recuperar a informação:

public string Edita(Livro livro ){
    livro.Id; //pega o id que veio dor form
    livro.Titulo; //pega o titulo que veio do form
    livro.Autor; //pega o autor que veio do form
}

Também conseguimos receber informações simples como apenas um número ou texto também conseguimos pedir direto como parâmetro. Por exemplo, no caso de um link de remoção que manda um parâmetro id:

<a href="/livro/remove?id=5">Remover</a>

Podemos receber no método assim:

public string Remove(int id ){
    // restante da lógica
}

Ou no caso de uma busca de livros por autor em que o formulário manda um input com o nome do autor:

<form action="/livro/busca">
    <input type="text" name="nomeAutor">
    <button>Buscar</button>
</form>

recebemos esse nome do autor assim:

public string Busca(string nomeAutor){
    // restante da lógica
}

Assim não precisamos mais ficar recuperando as informações do request e convertendo para o tipo que precisamos. O próprio asp.net mvc modela a informação para você de acordo com a sua necessidade e facilita já o trabalho. Só precisamos informar alguma parâmetro que seja capaz de receber esta informação, seja uma classe de negócio ou até um tipo nativo da linguagem.

Muito obrigado pela resposta. Mas no meu caso não resolveu pois não sei como implementar quando uma das minhas propriedades implementa uma interface.

Contexto: Classe Cliente tem uma propriedade IDadosCadastrais DadosCadastrais; As classes PF e PJ implementam a interface DadosCadastrais.

Na hora de criar o modelo, o framework não entende que dependendo do radiobutton selecionado irá criar uma instancia diferente.

Pode me ajudar com essa questão? Qual seria a maneira CORRETA de solucionar essa questão?

Muito obrigado pela força.

Precisava dar uma como está o código para ver porque ele não está conseguindo fazer o model binding. Você pode me mandar exatamente como está a sua interface, as classes e os inputs dos formulário para eu dar uma olhada?

Claro, desde já agradeço a atenção.

Segue o projeto: https://drive.google.com/open?id=1gvCzX9gcFW5w8_-4nFq7T4jSNWUiM4ik

Não tem nada ... só estava tentando criar uma instancia da classe cliente através de uma view.

Tks.

Olá Rafael,

estou sem permissão de acesso ao link do drive. Configura lá para o link ter visibilidade pública.

Falha minha. Alterado.

Ok, vendo o código agora entendi o problema. Neste caso realmente não teria muito como fazer porque o model binding não saberia qual das classes instanciar para preencher a propriedade de DadosCadastrais.

Neste caso é quando a gente fala que os modelos que mapeiam as entidades do negócio e do banco ficaram diferentes dos dados que veem da camada de view, no caso um formulário.

A solução mais orientada a objetos que o pessoal vem adotando neste caso é trabalhar com o conceito de ViewModel. A ideia é ter uma classe que é responsável por receber exatamente por receber os dados de acordo com o que tem na tela. Então dado o que tem no seu Cadastro.cshtml por enquanto, você poderia ter uma ViewModel assim:

public class CadastroClienteViewModel {
    public string TipoCliente { get; set; }
        public String Nome { get; set; }
    public DateTime Nascimento { get; set; }
    public string CPF { get; set; }
        public string RG { get; set; }    
}

Ai em seu método do Controller receber esta classe como parãmetro:

public string NovoCliente(CadastroClienteViewModel cadastro) {
    //...
}

Ai dentro dessa classe de ViewModel teria um método CriaCliente que geraria o modelo de acordo com o que veio da tela. Como existe essa variação de acordo com o que veio do radio button, o método seria mais ou menos assim:

public class CadastroClienteViewModel {
    public string TipoCliente { get; set; }
    public String Nome { get; set; }
    public DateTime Nascimento { get; set; }
    public string CPF { get; set; }
    public string RG { get; set; }    

    public Cliente CriaCliente() 
    {
        Cliente cliente = new Cliente();

        //preenche propriedades comuns a todos os clientes

        if( this.TipoCliente.Equals("PF") ) {
            cliente.DadosCadastrais = new PF() {
                Nome = this.Nome,
                Nascimento = this.Nascimento, 
                //restante dos dados de PF
            };
        } else {
            cliente.DadosCadastrais = new PJ() {
                //restante dos dados de PJ
            };
        }

        return cliente;
    }
}

Ai para recuperar o Cliente bastaria chamar o método:

public string NovoCliente(CadastroClienteViewModel cadastro) {
    Cliente cliente = cadastro.CriaCliente();
}

Pronto, assim a lógica de saber lidar com o que vem da tela e como traduzir isso para as suas entidades fica isolado dentro de uma única classe que tem apenas essa responsabilidade. E se algum dia a View mudar sua estrutura, seus inputs, etc, você precisaria apenas alterar as propriedades da classe CadastroClienteViewModel e o método CriaCliente que o restante se manterá intacto.

Agora sim.... ;)

Muito obrigado. Implementado e funcionando.

Agora vem a parte difícil, fazer isso funcionar com o Entity uahuaa... mas irei abrir outro tópico para ficar mais organizado.

Obrigado.

Opa, bateu uma dúvida:

Criei na classe CadastroClienteViewModel uma propriedade do tipo "bool" e adicionei um controle do tipo input checkbox de mesmo nome na minha view. Porém esta propriedade retorna sempre FALSE, como posso recuperar um valor booleano da minha view?

public bool Utilizador { get; set; }
<input name="Utilizador" type="checkbox"/>

O problema é que o checkbox não soube qual valor enviar quando ele está checado. Para fazer isso é só informar o value dele com true:

<input name="Utilizador" type="checkbox" value="true"/>