Por que o cuidado ASP.NET MVC sobre a minha leitura apenas as propriedades durante a ligação de dados?

StackOverflow https://stackoverflow.com/questions/2211829

Pergunta

Editar: recompensa, porque eu estou procurando uma solução MVC3 (se existir) Adicionado diferente deste:

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;


Eu tenho uma leitura única propriedade no meu 'Address' modelo 'CityStateZip'.

É apenas uma maneira conveniente de obter cidade, estado, CEP a partir de um endereço nos EUA. Ele lança uma exceção se o país não está EUA (o chamador deve verificar primeiro).

    public string CityStateZip
    {
        get
        {
            if (IsUSA == false)
            {
                throw new ApplicationException("CityStateZip not valid for international addresses!");
            }

            return (City + ", " + StateCd + " " + ZipOrPostal).Trim().Trim(new char[] {','});
        }
    }

Isso faz parte do meu modelo para que ele fica ligado. Antes de ASP.NET MVC2 RC2 neste campo não causou um problema durante a ligação de dados. Eu nunca nem pensei sobre isso -. Depois de tudo isso só é somente leitura

Agora, porém, com o lançamento RC2 janeiro 2010 dá-me um erro durante a ligação de dados -. Becasue o fichário de modelo padrão parece querer verificar este valor (mesmo que seja somente leitura)

É a linha 'base.OnModelUpdated' que causa esse erro para ser disparado.

public class AddressModelBinder : DefaultModelBinder
{
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        base.OnModelUpdated(controllerContext, bindingContext);

Últimas minutos alterações ao ModelBinder evidentemente causou essa mudança de comportamento - mas eu ainda não estou muito certo o que os repurcussions de que são - ou se este é ou não um bug? Estou passando este para a equipe MVC, mas curioso para saber se alguém tem alguma sugestão, entretanto, como posso impedir que esta propriedade de ligação.

Este artigo vale a pena ler sobre as mudanças - mas não menciona propriedades somente leitura em todos (não que eu esperaria que ele). A questão (se houver) pode ser mais ampla do que esta situação - eu não sou apenas certo sobre quaisquer repurcussions - se houver

Input Validation vs. Validação do Modelo em ASP.NET MVC


Como solicitado pelo @haacked aqui está o stacktrace:

Eu recebo isso simplesmente adicionando o seguinte linha para qualquer modelo e fazer um post para o método de ação correspondente. Neste caso eu adicionei-o ao meu modelo mais simples possível.

 public string Foo { get { throw new Exception("bar"); } }

[TargetInvocationException: acessor Propriedade 'Foo' no objeto 'Rolling_Razor_MVC.Models.ContactUsModel' jogou a seguinte exceção: 'bar'] System.ComponentModel.ReflectPropertyDescriptor.GetValue (componente Object) 390 System.Web.Mvc. <> C__DisplayClassb. b__a () 18 System.Web.Mvc.ModelMetadata.get_Model () 22 System.Web.Mvc.ModelMetadata.get_RealModelType () 29 System.Web.Mvc. d__0.MoveNext () 38 System.Linq. d__14`2.MoveNext () 273 System.Web.Mvc. d__5.MoveNext () 644 System.Web.Mvc.DefaultModelBinder.OnModelUpdated (ControllerContext ControllerContext, ModelBindingContext bindingContext) 92 System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel (ControllerContext ControllerContext, ModelBindingContext bindingContext, Object Model) +60 System.Web.Mvc.DefaultModelBinder.BindComplexModel (ControllerContext ControllerContext, ModelBindingContext bindingContext) 1048 System.Web.Mvc.DefaultModelBinder.BindModel (ControllerContext ControllerContext, ModelBindingContext bindingContext) 280 System.Web.Mvc.Controller.TryUpdateModel (modelo TModel, cadeia de prefixo, String [] includeProperties, String [] excludeProperties, IValueProvider ValueProvider) +449 System.Web.Mvc.Controller.TryUpdateModel (modelo TModel) 73

Foi útil?

Solução

Eu acredito que eu estou enfrentando um problema semelhante. Eu publiquei os detalhes:

http://forums.asp.net/t/1523362.aspx


Editar : Resposta da equipe MVC (de cima URL):

Nós investigamos isso e concluiu que o sistema de validação está se comportando como esperado. Desde validação do modelo envolve a tentativa de executar a validação sobre todas as propriedades, e desde que não anuláveis ??propriedades do tipo valor tem um atributo implícita [Obrigatório], estamos validando essa propriedade e chamando seu getter no processo. Entendemos que esta é uma alteração de quebra de V1 do produto, mas é necessário fazer o novo sistema de validação do modelo operar corretamente.

Você tem algumas opções para contornar este. Qualquer um destes deve funcionar:

  • Altere a propriedade Data a um método em vez de uma propriedade; Desta forma, ele será ignorado pelo framework MVC.
  • Alterar o tipo de propriedade para DateTime? em vez de DateTime. Isso remove o implícito [Obrigatório] a partir desta propriedade.
  • Desmarque a bandeira DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes estáticos. Isto remove o implícito [Necessário] a partir de todas as propriedades do tipo de valor não nulo aplicação à escala. Nós estamos considerando a adição de V3 do produto um atributo que vai sinalizar para nós "não vinculá-lo, não validá-lo, basta fingir que esta propriedade não existe."

Obrigado novamente para o relatório!

Outras dicas

Ainda tendo o mesmo problema com MVC3.

Eu acho que a melhor maneira é só para isso em global.asax (de resposta de SevenCentral):

 DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

Isso irá desativar para todos eles

Isso parece para todo o mundo como um bug para mim. I totalmente não pode compreender porque o ModelBinder precisa verificar minha leitura apenas propriedades (pode haver alguns aspectos técnicos, mas eu definitivamente não entendo, e não estou disposto a passar o tempo tentando).

Eu adicionei o seguinte Provider Modelo Meta Data em que a minha solução para contornar o problema

protected override CachedDataAnnotationsModelMetadata CreateMetadataPrototype(IEnumerable<Attribute> attributes, Type containerType, Type modelType, string propertyName)
{
    var metadata = base.CreateMetadataPrototype(attributes, containerType, modelType, propertyName);

    if (metadata.IsReadOnly)
    {
        metadata.IsRequired = false;
    }

    return metadata;
}

protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func<object> modelAccessor)
{
    var metadata = base.CreateMetadataFromPrototype(prototype, modelAccessor);

    if (prototype.IsReadOnly)
    {
        metadata.IsRequired = false;
    }

    return metadata;
}

Você também precisará adicionar o seguinte para Global.asax.cs

protected void Application_Start()
{
    ModelMetadataProviders.Current = new RESModelMetadataProvider();
    ModelBinders.Binders.Add(typeof(SmartDate), new SmartDateModelBinder());

    ...
}

É claro que eu acho que eu poderia converter CityStateZip para GetCityStateZip() mas então eu não posso obrigá-la em algo como o Silverlight tão facilmente. Este trabalho poder para uma correção temporária para qualquer outra pessoa tendo esse problema.

Eu tenho exatamente o mesmo problema !!

Para mais informações sobre o meu problema, você pode visitar ASP.NET MVC 2.0 não utilizado propriedade Modelo sendo chamado ao postar um produto para o servidor?

faz esta necessidade queremos dizer para programar nossas propriedades com a suposição de que eles vão ser chamado inesperadamente (antes de propriedades que ele depende estão configurados / inicializado etc) ... se assim for, isso representa uma mudança em nossas práticas de programação e eu gostaria de saber como proceder.

Enquanto isso, eu só tenho um simples 'se' verificar que livra o problema.

Eu estava tendo um problema semelhante, um campo que eu não esperava para ser validado estava recebendo um erro quando o formulário enviada de volta para o controlador. Depois de algum googling, me deparei com http://codeblog.shawson.co.uk/mvc-strongly-typed-view-returns-a-null-model-on-post-back/ onde foi apontado que conflitos nome poderia causar problemas.

Embora eu não acho que a minha classe post-back variável tinha conflitantes nomes de propriedades, renomear a propriedade receber o erro resolveu o meu problema.

O mesmo problema ainda existe em MVC 5.2.3, e nem sequer é o código de validação causando o problema. O DefaultModelBinder chama os getters fora de seu código de validação, mesmo se eles são propriedades somente leitura e até mesmo se nenhum dado solicitação está sendo passada para o controlador combinando essas propriedades.

Veja uma explicação mais detalhada e minha solução completa aqui: https://stackoverflow.com/a/54431404/10987278.

Eu não tenho certeza se essa solução pode ser reformulado para trabalhar com MVC 3, mas espero que possa ajudar os outros ainda sofrem com o mesmo problema na versão posterior do MVC que tropeçou em toda esta questão como eu fiz.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top