Alguém pode me dar uma definição sucinta da função de ModelState no Asp.net MVC (ou um link para um). Em particular, preciso saber em que situações é necessário ou desejável ligar ModelState.Clear()
.
Um pouco aberto acabou hein ... desculpe, eu acho que pode ajudar se te contar o que estou fazendo de forma aguda:
Eu tenho uma ação de edição em um controlador chamado "Página". Quando vejo o formulário para alterar os detalhes da página, tudo carrega bem (vinculado a um objeto "MyCmsPage"). Em seguida, clico em um botão que gera um valor para um dos campos do objeto MyCmsPage ( MyCmsPage.SeoTitle
). Ele gera e atualiza o objeto e eu, então, retorno o resultado da ação com o objeto da página recém-modificado e espero que a caixa de texto relevante (renderizada usando <%= Html.TextBox("seoTitle", page.SeoTitle)%>
) seja atualizada ... mas, infelizmente, exibe o valor do modelo antigo que foi carregado.
Eu trabalhei em torno disso usando, ModelState.Clear()
mas preciso saber por que / como funcionou, então não estou fazendo isso às cegas.
Controlador de página:
[AcceptVerbs("POST")]
public ActionResult Edit(MyCmsPage page, string submitButton)
{
// add the seoTitle to the current page object
page.GenerateSeoTitle();
// why must I do this?
ModelState.Clear();
// return the modified page object
return View(page);
}
Aspx:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyCmsPage>" %>
....
<div class="c">
<label for="seoTitle">
Seo Title</label>
<%= Html.TextBox("seoTitle", page.SeoTitle)%>
<input type="submit" value="Generate Seo Title" name="submitButton" />
</div>
fonte
Respostas:
Acho que é um bug no MVC. Lutei com esse problema por horas hoje.
Dado isso:
A visualização é renderizada com o modelo original, ignorando as alterações. Então pensei, talvez ele não goste de eu usar o mesmo modelo, então tentei assim:
E ainda assim a visualização renderiza com o modelo original. O que é estranho é que, quando coloco um ponto de interrupção na visualização e examino o modelo, ele tem o valor alterado. Mas o fluxo de resposta tem os valores antigos.
Eventualmente, descobri o mesmo trabalho em torno que você fez:
Funciona conforme o esperado.
Não acho que isso seja um "recurso", não é?
fonte
Atualizar:
View()
de uma ação POST. Em vez disso, use PRG e redirecione para GET se a ação for um sucesso.View()
de uma ação POST, faça-o para validação do formulário e faça-o da maneira que o MVC foi projetado usando os auxiliares integrados. Se você fizer isso dessa forma, não precisará usar.Clear()
ModelState
pois você não deveria usá-lo de qualquer maneira.Resposta antiga:
ModelState em MVC é usado principalmente para descrever o estado de um objeto de modelo em grande parte com relação a se esse objeto é válido ou não. Este tutorial deve explicar muito.
Geralmente, você não precisa limpar o ModelState, pois ele é mantido pelo mecanismo MVC para você. Limpá-lo manualmente pode causar resultados indesejados ao tentar aderir às melhores práticas de validação MVC.
Parece que você está tentando definir um valor padrão para o título. Isso deve ser feito quando o objeto do modelo é instanciado (camada de domínio em algum lugar ou no próprio objeto - ctor sem parâmetros), na ação get de forma que desça para a página pela primeira vez ou completamente no cliente (via ajax ou algo assim) de modo que parece que o usuário o inseriu e ele volta com a coleção de formulários postados. De alguma forma, a sua abordagem de adicionar este valor ao receber uma coleção de formulários (na ação POST // Editar) está causando esse comportamento bizarro que pode
.Clear()
parecer funcionar para você. Confie em mim - você não quer usar o claro. Experimente uma das outras ideias.fonte
Se você deseja limpar um valor para um campo individual, achei a seguinte técnica útil.
Observação: altere "Chave" para o nome do campo que você deseja redefinir.
fonte
Bem, o ModelState basicamente mantém o estado atual do modelo em termos de validação, ele mantém
ModelErrorCollection: Representa os erros quando o modelo tenta vincular os valores. ex.
ou como um parâmetro no ActionResult
ValueProviderResult : contém os detalhes sobre a tentativa de vinculação ao modelo. ex. AttemptedValue, Culture, RawValue .
O método Clear () deve ser usado com cuidado, pois pode levar a resultados inesperados. E você perderá algumas propriedades interessantes do ModelState como AttemptedValue, isso é usado pelo MVC em segundo plano para preencher novamente os valores do formulário em caso de erro.
fonte
Tive uma instância em que queria atualizar o modelo de um formulário submetido e não queria 'Redirecionar para a ação' por motivos de desempenho. Os valores anteriores de campos ocultos estavam sendo mantidos em meu modelo atualizado - causando todos os tipos de problemas!
Algumas linhas de código logo identificaram os elementos dentro de ModelState que eu queria remover (após a validação), então os novos valores foram usados na forma: -
fonte
Bem, muitos de nós parecem ter sido mordidos por isso, e embora o motivo pelo qual isso acontece faça sentido, eu precisava de uma maneira de garantir que o valor em meu Model fosse mostrado, e não ModelState.
Alguns sugeriram
ModelState.Remove(string key)
, mas não é óbvio o quekey
deveria ser, especialmente para modelos aninhados. Aqui estão alguns métodos que criei para ajudar nisso.O
RemoveStateFor
método pegará umModelStateDictionary
, um Modelo e uma expressão para a propriedade desejada e os removerá.HiddenForModel
pode ser usado em sua Visualização para criar um campo de entrada oculto usando apenas o valor do Modelo, removendo primeiro sua entrada ModelState. (Isso pode ser facilmente expandido para os outros métodos de extensão auxiliares).Chame de um controlador como este:
ou de uma visão como esta:
Ele usa
System.Web.Mvc.ExpressionHelper
para obter o nome da propriedade ModelState.fonte
Eu queria atualizar ou redefinir um valor se ele não fosse validado e encontrei este problema.
A resposta fácil, ModelState.Remove, é ... problemática ... porque se você estiver usando ajudantes, você não sabe realmente o nome (a menos que siga a convenção de nomenclatura). A menos que você crie uma função que tanto seu auxiliar personalizado quanto seu controlador possam usar para obter um nome.
Este recurso deveria ter sido implementado como uma opção no helper, onde por padrão não faz isso, mas se você quiser que a entrada não aceita seja exibida novamente, você pode apenas dizer isso.
Mas pelo menos eu entendo o problema agora;).
fonte
Remove()
na chave correta.Entendi no final. Meu ModelBinder personalizado que não estava sendo registrado e faz o seguinte:
Portanto, algo que a vinculação do modelo padrão estava fazendo deve ter causado o problema. Não tenho certeza do que, mas pelo menos meu problema foi corrigido agora que meu fichário de modelo personalizado está sendo registrado.
fonte
Geralmente, quando você está lutando contra as práticas padrão de uma estrutura, é hora de reconsiderar sua abordagem. Nesse caso, o comportamento de ModelState. Por exemplo, quando você não quer o estado do modelo após um POST, considere um redirecionamento para o get.
EDITADO para responder a comentários culturais:
Aqui está o que eu uso para lidar com um aplicativo MVC multicultural. Primeiro, as subclasses do gerenciador de rota:
E é assim que faço a conexão das rotas. Depois de criar as rotas, acrescento meu subagente (example.com/subagent1, example.com/subagent2, etc) e o código de cultura. Se tudo que você precisa é a cultura, simplesmente remova o subagente dos manipuladores de rota e rotas.
fonte
Bem, isso pareceu funcionar na minha página do Razor e nunca fiz uma viagem de ida e volta para o arquivo .cs. Esta é a velha maneira de html. Pode ser útil.
fonte