为什么ASP。NET MVC关心我的只读属性在数据库中吗?

时间:2021-07-11 20:58:08

Edit: Added bounty because I'm seeking an MVC3 solution (if one exists) other than this:

编辑:添加bounty因为我正在寻找MVC3解决方案(如果存在),而不是这个:

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

DataAnnotationsModelValidatorProvider。AddImplicitRequiredAttributeForValueTypes = false;


I have a read only property on my 'Address' model 'CityStateZip'.

我有一个只读属性在我的'地址'模型'CityStateZip'。

It's just a convenient way to get city, state, zip from a US address. It throws an exception if the country is not USA (the caller is supposed to check first).

这只是一种方便的方式,从一个美国地址获得城市,州,zip。如果这个国家不是美国,它会抛出一个例外(打电话的人应该先检查)。

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

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

This is part of my model so it gets bound. Prior to ASP.NET MVC2 RC2 this field never caused a problem during databinding. I never even really thought about it - after all it is only read only.

这是模型的一部分。在ASP。此字段在数据绑定期间从未造成问题。我从来没有真正想过它——毕竟它是只读的。

Now though with the January 2010 RC2 release it gives me an error during databinding - becasue the default model binder seems to want to check this value (even though it is read only).

现在,虽然在2010年1月的RC2版本中,它给了我一个在databinding期间的错误,因为默认的模型绑定器似乎想要检查这个值(尽管它只被读取)。

It is the 'base.OnModelUpdated' line that causes this error to be triggered.

这是基础。onmodelupdates ' line,导致触发此错误。

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

Last minutes changes to the modelbinder evidently caused this change in behavior - but I'm not quite sure yet what the repurcussions of it are - or whether or not this is a bug? I'm passing this on to the MVC team but curious if anyone else has any suggestions in the meantime how I can prevent this property from binding.

最后几分钟,对modelbinder的修改显然导致了行为上的改变——但我还不确定它是什么——或者这是否是一个bug?我将这个问题传递给MVC团队,但是我想知道在此期间是否有其他人对如何防止这个属性绑定有什么建议。

This article is well worth reading about the changes - but doesn't mention readonly properties at all (not that I would expect it to). The issue (if there is one) may be broader than this situation - I'm just not sure about any repurcussions - if any!

这篇文章非常值得一读,但是根本没有提到readonly属性(我并不期望它这么做)。这个问题(如果有的话)可能比这种情况更广泛——我只是不确定是否会有什么后果——如果有的话!

Input Validation vs. Model Validation in ASP.NET MVC

在ASP中输入验证和模型验证。NET MVC


As requested by @haacked here's the stacktrace :

应@haacked的要求,这里是stacktrace:

I get this by simply adding the following line to ANY model and making a post to the corresponding action method. In this instance I added it to my simplest possible model.

我只需要在任何模型中添加以下一行并对相应的操作方法进行post,就可以得到这个结果。在本例中,我将它添加到最简单的可能模型中。

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

[TargetInvocationException: Property accessor 'Foo' on object 'Rolling_Razor_MVC.Models.ContactUsModel' threw the following exception:'bar'] System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component) +390 System.Web.Mvc.<>c__DisplayClassb.<GetPropertyValueAccessor>b__a() +18 System.Web.Mvc.ModelMetadata.get_Model() +22 System.Web.Mvc.ModelMetadata.get_RealModelType() +29 System.Web.Mvc.<GetValidatorsImpl>d__0.MoveNext() +38 System.Linq.<SelectManyIterator>d__14`2.MoveNext() +273 System.Web.Mvc.<Validate>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(TModel model, String prefix, String[] includeProperties, String[] excludeProperties, IValueProvider valueProvider) +449 System.Web.Mvc.Controller.TryUpdateModel(TModel model) +73

[TargetInvocationException:对象'Rolling_Razor_MVC.Models的属性访问器'Foo'。ContactUsModel'抛出了以下异常:'bar'] System.ComponentModel.ReflectPropertyDescriptor。 b__a() +18 system . web.mvc.modeladata.get_model () +22 system . web.web.web_web_model () . mvc++ web_model . web_model . web_model . mvc++ model . web_model . mvc++ model . mvc++ model . mvext . fext . fext . mvc++onmodelupdate (ControllerContext ControllerContext ControllerContext context、ModelBindingContext bindingContext) +92 System.Web.Mvc.DefaultModelBinder。BindComplexElementalModel(ControllerContext ControllerContext ControllerContext上下文、ModelBindingContext bindingContext、对象模型)+60 system . web . web . mvc . defaultmodelbinder。BindComplexModel(ControllerContext ControllerContext context, ModelBindingContext bindingContext bindingContext context context) +1048 System.Web.Mvc.DefaultModelBinder。BindModel(ControllerContext ControllerContext ControllerContext context、ModelBindingContext bindingContext) +280 System.Web.Mvc.Controller。TryUpdateModel(TModel, String前缀,String[] includeProperties, String[] exclusive deproperties, IValueProvider valueProvider) +449 System.Web.Mvc.Controller。TryUpdateModel(TModel模型)+ 73

6 个解决方案

#1


16  

I believe I'm experiencing a similar issue. I've posted the details:

我相信我也遇到过类似的问题。我发布的细节:

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

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


edit: Response from MVC team (from above URL):

编辑:MVC团队响应(来自以上URL):

We investigated this and have concluded that the validation system is behaving as expected. Since model validation involves attempting to run validation over all properties, and since non-nullable value type properties have an implicit [Required] attribute, we're validating this property and calling its getter in the process. We understand that this is a breaking change from V1 of the product, but it's necessary to make the new model validation system operate correctly.

我们对此进行了调查,并得出结论,验证系统运行正常。由于模型验证涉及尝试在所有属性上运行验证,并且由于非空值类型属性有一个隐式的[Required]属性,我们正在验证这个属性并在过程中调用它的getter。我们知道这是产品V1的一个突破性的变化,但是有必要使新的模型验证系统正确运行。

You have a few options to work around this. Any one of these should work:

你有几个选择来解决这个问题。其中任何一个都应该有效:

  • Change the Date property to a method instead of a property; this way it will be ignored by the MVC framework.
  • 将日期属性更改为方法而不是属性;这样,MVC框架就会忽略它。
  • Change the property type to DateTime? instead of DateTime. This removes the implicit [Required] from this property.
  • 将属性类型更改为DateTime?而不是DateTime。这将从该属性中删除隐式[Required]。
  • Clear the static DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes flag. This removes the implicit [Required] from all non-nullable value type properties application-wide. We're considering adding in V3 of the product an attribute which will signal to us "don't bind it, don't validate it, just pretend that this property doesn't exist."
  • 明确静态DataAnnotationsModelValidatorProvider。AddImplicitRequiredAttributeForValueTypes国旗。这将从应用程序范围内的所有非空值类型属性中删除隐式[Required]。我们正在考虑在产品的V3中添加一个属性,这个属性会告诉我们“不要绑定它,不要验证它,只是假装这个属性不存在。”

Thanks again for the report!

再次感谢你的报告!

#2


2  

Still having the same issue with MVC3.

MVC3也有同样的问题。

I think the best way is to just to this in global.asax (from SevenCentral's answer):

我认为最好的办法就是在全球范围内这么做。asax(从SevenCentral的回答):

 DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

This will disable for all of them

这将禁用所有的

#3


1  

This looks for all the world like a bug to me. I fully can't understand why the ModelBinder needs to check my read only properties (there may be some technicalities, but I definitely don't understand, and am not willing to spend the time trying to).

这对我来说就像一只虫子。我完全无法理解为什么ModelBinder需要检查我的只读属性(可能有一些技术细节,但我绝对不理解,而且我不愿意花时间去尝试)。

I added the following Model Meta Data Provider in to my solution to get round the problem

我在我的解决方案中添加了以下模型元数据提供程序以解决这个问题

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;
}

You will also need to add the following to Global.asax.cs

您还需要在Global.asax.cs中添加以下内容

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

    ...
}

#4


0  

Of course I guess I could convert CityStateZip to GetCityStateZip() but then I cant bind it in something like silverlight quite as easily. This might work for a temporary fix for anyone else experiencing this issue.

当然,我想我可以将CityStateZip转换为GetCityStateZip(),但是我不能像silverlight那样很容易地将其绑定。这对于任何遇到此问题的人来说都是暂时的修复。

#5


0  

I HAVE THE EXACT SAME PROBLEM!!

我也有同样的问题!!

For more information about my issue, you may visit ASP.NET MVC 2.0 Unused Model Property being called when posting a product to the server?

有关我的问题的更多信息,你可以访问ASP。当向服务器发布产品时,会调用NET MVC 2.0未使用的模型属性吗?

does this mean we need to program our properties with the assumption that they'll be called unexpectedly (before properties which it depends on are set up/initialized etc)... if so, this represents a change in our programming practices and i would like to know how to proceed.

这是否意味着我们需要对我们的属性进行编程,假定它们会被意外地调用(在它所依赖的属性被设置/初始化等之前)……如果是这样,这代表了我们编程实践中的一个变化,我想知道如何继续。

meanwhile, i just have a simple 'if' check that rids the problem.

与此同时,我只有一个简单的“如果”检查来解决问题。

#6


0  

I was having a similar problem, a field which I did not expect to be validated was receiving an error when the form posted back to the controller. After some googling, I came across http://codeblog.shawson.co.uk/mvc-strongly-typed-view-returns-a-null-model-on-post-back/ where it was pointed out that name conflicts could cause problems.

我遇到了类似的问题,一个我不希望被验证的字段在表单提交回控制器时接收到错误。在谷歌上搜索之后,我发现了http://codeblog.shawson.co。在uk/mvc-强类型视图-returns-a-null-model-on- back/中指出,名称冲突可能导致问题。

Though I did not think my post-back variable class had conflicting property names, renaming the property receiving the error solved my problem.

虽然我不认为我的后端变量类有冲突的属性名,但是重命名接收错误的属性解决了我的问题。

#1


16  

I believe I'm experiencing a similar issue. I've posted the details:

我相信我也遇到过类似的问题。我发布的细节:

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

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


edit: Response from MVC team (from above URL):

编辑:MVC团队响应(来自以上URL):

We investigated this and have concluded that the validation system is behaving as expected. Since model validation involves attempting to run validation over all properties, and since non-nullable value type properties have an implicit [Required] attribute, we're validating this property and calling its getter in the process. We understand that this is a breaking change from V1 of the product, but it's necessary to make the new model validation system operate correctly.

我们对此进行了调查,并得出结论,验证系统运行正常。由于模型验证涉及尝试在所有属性上运行验证,并且由于非空值类型属性有一个隐式的[Required]属性,我们正在验证这个属性并在过程中调用它的getter。我们知道这是产品V1的一个突破性的变化,但是有必要使新的模型验证系统正确运行。

You have a few options to work around this. Any one of these should work:

你有几个选择来解决这个问题。其中任何一个都应该有效:

  • Change the Date property to a method instead of a property; this way it will be ignored by the MVC framework.
  • 将日期属性更改为方法而不是属性;这样,MVC框架就会忽略它。
  • Change the property type to DateTime? instead of DateTime. This removes the implicit [Required] from this property.
  • 将属性类型更改为DateTime?而不是DateTime。这将从该属性中删除隐式[Required]。
  • Clear the static DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes flag. This removes the implicit [Required] from all non-nullable value type properties application-wide. We're considering adding in V3 of the product an attribute which will signal to us "don't bind it, don't validate it, just pretend that this property doesn't exist."
  • 明确静态DataAnnotationsModelValidatorProvider。AddImplicitRequiredAttributeForValueTypes国旗。这将从应用程序范围内的所有非空值类型属性中删除隐式[Required]。我们正在考虑在产品的V3中添加一个属性,这个属性会告诉我们“不要绑定它,不要验证它,只是假装这个属性不存在。”

Thanks again for the report!

再次感谢你的报告!

#2


2  

Still having the same issue with MVC3.

MVC3也有同样的问题。

I think the best way is to just to this in global.asax (from SevenCentral's answer):

我认为最好的办法就是在全球范围内这么做。asax(从SevenCentral的回答):

 DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

This will disable for all of them

这将禁用所有的

#3


1  

This looks for all the world like a bug to me. I fully can't understand why the ModelBinder needs to check my read only properties (there may be some technicalities, but I definitely don't understand, and am not willing to spend the time trying to).

这对我来说就像一只虫子。我完全无法理解为什么ModelBinder需要检查我的只读属性(可能有一些技术细节,但我绝对不理解,而且我不愿意花时间去尝试)。

I added the following Model Meta Data Provider in to my solution to get round the problem

我在我的解决方案中添加了以下模型元数据提供程序以解决这个问题

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;
}

You will also need to add the following to Global.asax.cs

您还需要在Global.asax.cs中添加以下内容

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

    ...
}

#4


0  

Of course I guess I could convert CityStateZip to GetCityStateZip() but then I cant bind it in something like silverlight quite as easily. This might work for a temporary fix for anyone else experiencing this issue.

当然,我想我可以将CityStateZip转换为GetCityStateZip(),但是我不能像silverlight那样很容易地将其绑定。这对于任何遇到此问题的人来说都是暂时的修复。

#5


0  

I HAVE THE EXACT SAME PROBLEM!!

我也有同样的问题!!

For more information about my issue, you may visit ASP.NET MVC 2.0 Unused Model Property being called when posting a product to the server?

有关我的问题的更多信息,你可以访问ASP。当向服务器发布产品时,会调用NET MVC 2.0未使用的模型属性吗?

does this mean we need to program our properties with the assumption that they'll be called unexpectedly (before properties which it depends on are set up/initialized etc)... if so, this represents a change in our programming practices and i would like to know how to proceed.

这是否意味着我们需要对我们的属性进行编程,假定它们会被意外地调用(在它所依赖的属性被设置/初始化等之前)……如果是这样,这代表了我们编程实践中的一个变化,我想知道如何继续。

meanwhile, i just have a simple 'if' check that rids the problem.

与此同时,我只有一个简单的“如果”检查来解决问题。

#6


0  

I was having a similar problem, a field which I did not expect to be validated was receiving an error when the form posted back to the controller. After some googling, I came across http://codeblog.shawson.co.uk/mvc-strongly-typed-view-returns-a-null-model-on-post-back/ where it was pointed out that name conflicts could cause problems.

我遇到了类似的问题,一个我不希望被验证的字段在表单提交回控制器时接收到错误。在谷歌上搜索之后,我发现了http://codeblog.shawson.co。在uk/mvc-强类型视图-returns-a-null-model-on- back/中指出,名称冲突可能导致问题。

Though I did not think my post-back variable class had conflicting property names, renaming the property receiving the error solved my problem.

虽然我不认为我的后端变量类有冲突的属性名,但是重命名接收错误的属性解决了我的问题。