实现写入类内属性的类级验证属性

发布于 2024-09-08 10:27:53 字数 2535 浏览 5 评论 0原文

我正在构建一个 ASP.NET MVC 站点,我想在其中使用验证属性来装饰我的 ViewModel。我想验证的一件事是用户通过表单提交的地址是可地理编码的。为此,我已经创建了一个自定义 ValidationAttribute 并应用于我的 StreetAddress 属性。

这一切都很好,只是我实际上发出了两个地理编码请求 - 一个在我的 ViewModel 中进行验证,另一个在我的控制器中将纬度和经度输入到我的数据库中。我想减少不必要的网络使用和延迟,因此我需要通过 将验证地理编码的结果输入到我的控制器中。

为了完成这样的事情,我想我应该在我的 ViewModel 中创建一个纬度和经度属性。视图本身不会触及这两个属性,但验证属性将报告地理编码失败并返回视图或将结果写入属性中。

对于要访问 3 个属性的验证属性,必须将其应用于整个类。 我还不知道该怎么做,但这就是这个问题的目的。

更新:感谢这个答案,我已经弄清楚如何创建类级验证属性。 答案中的链接还演示了如何读取类内属性的内容(通过反射)。不过,我仍然不知道如何写入属性。


我的问题

如何创建可应用于整个类的ValidationAttribute?下面,我发布了我想要转换为可应用于我的 ViewModel 的属性的代码:

public class GeocodableAttribute : ValidationAttribute
    {
        public GeocodableAttribute() : base()
        {
            ErrorMessage = "We weren't able to find that location.";
        }
        public override bool IsValid(object value)
        {
            if (value == null) //we don't care if it's required or not.
            {
                return true;
            }
            var address = (string)value;
            var response = Geocoder.CallGeoWS(address.Trim());
            if(response.Status=="ZERO_RESULTS")
            {
                return false;
            }
            return true;
        }
    }


如何将属性写入类中的某些属性 它适用于什么?当我将此属性应用于 ViewModel 时,我希望它将成功的地理编码结果写入两个属性并返回 true。我怎样才能实现呢?

更新#2:我想我刚刚弄清楚如何写入属性。下面的代码应该工作吗?

    private static void WritePropertyValue(object obj, string propertyName, object valueToWrite)
    {
        if (obj == null) return null;
        var type = obj.GetType();
        var propertyInfo = type.GetProperty(propertyName);
        if (propertyInfo == null) return null;
        propertyInfo.SetValue(obj, valueToWrite, null);
    }

这会破坏对其他属性/属性的客户端验证吗? 我的 ViewModel 中有其他属性,我用内置的 ValidationAttributes 装饰了这些属性,例如 [Required][范围]。我还为它们启用了客户端验证。将我的新属性应用于整个 ViewModel 类是否会完全破坏客户端验证,或者是否会在客户端上执行其他属性的验证,然后在服务器上执行总体验证?

I'm building an ASP.NET MVC site where I want to decorate my ViewModels with validation attributes. One of the things I want to validate is that the address that a user submits through a form is geocodable. For that, I have already created a custom ValidationAttribute and have applied to my StreetAddress property.

This is all good, except that I am actually making two geocoding requests - one in my ViewModel for validation and another in my Controller to input the latitude and longitude into my database. I want to cut down on unnecessary network usage and delays, so I need to pass the
result from the validation geocode into my controller.

To accomplish such a thing, I think I should create a Latitude and Longitude property in my ViewModel. The View itself won't touch these 2 properties, but the validation attribute will either report a failure in geocoding and return the View or write the results into the properties.

For a validation attribute to access 3 properties, it has to be applied to the whole class. I don't know how to do that yet, but that's what this question is for.

UPDATE: Thanks to this answer, I have figured out how to create a class-level validation attribute. The link in the answer also demonstrates how to read the contents of a property inside the class (via Reflection). I still haven't figured out how to write to a property, though.


My Questions

How do I create a ValidationAttribute that can be applied to a whole class? Below, I have posted the code that I want to transfrom into an attribute that can be applied to my ViewModel:

public class GeocodableAttribute : ValidationAttribute
    {
        public GeocodableAttribute() : base()
        {
            ErrorMessage = "We weren't able to find that location.";
        }
        public override bool IsValid(object value)
        {
            if (value == null) //we don't care if it's required or not.
            {
                return true;
            }
            var address = (string)value;
            var response = Geocoder.CallGeoWS(address.Trim());
            if(response.Status=="ZERO_RESULTS")
            {
                return false;
            }
            return true;
        }
    }


How do I have the attribute write to certain properties in the class that it is applied to? When I apply this attribute to my ViewModel, I want it to write successful geocoding results into two properties and return true. How can I implement that?

UPDATE #2: I think I just figured out how to write to a property. Should the following code work?

    private static void WritePropertyValue(object obj, string propertyName, object valueToWrite)
    {
        if (obj == null) return null;
        var type = obj.GetType();
        var propertyInfo = type.GetProperty(propertyName);
        if (propertyInfo == null) return null;
        propertyInfo.SetValue(obj, valueToWrite, null);
    }

Will this break client-side validation for other attributes/properties? I have other properties in my ViewModel that I have decorated with built-in ValidationAttributes, such as [Required] and [Range]. I have also enabled client-side validation for them. Will applying my new attribute to the whole ViewModel class completely break client-side validation or will validation for the other properties be performed on the client and then total validation will be performed on the server?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

九局 2024-09-15 10:27:53

1) 您无法通过属性级别 ValidationAttribute 访问外部类。

您可以使用自定义模型绑定器来完成此操作。只需检测属性并进行相应验证即可。

创建自定义模型绑定器:
http://www.singingeels.com/Articles/Model_Binders_in_ASPNET_MVC.aspx

2) 否你尝试过吗?

这几乎是重复的。我会检查我的重复提交的问题和答案。它可能包含一个单独的技术,类级别验证,可以满足您的需要。

1) You can't access the outer class via a property level ValidationAttribute.

You could use a custom model binder to accomplish this. Simply detect the attributes and validate accordingly.

Creating a custom model binder:
http://www.singingeels.com/Articles/Model_Binders_in_ASPNET_MVC.aspx

2) No. Did you try?

This is almost a duplicate. I'd check out the question and answers for my dupe submission. It may contain a separate technique, class level validation, that may do what you need.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文