ASP.NET MVC 2 中具有数据存储访问权限的自定义 DataAnnotation 属性

发布于 2024-08-28 06:19:12 字数 1954 浏览 6 评论 0原文

如果我们需要支持另一个数据存储,我的应用程序设计时会实现存储库模式,并且我的代码会为将来可选的依赖项注入做好准备。

我想为我的内容对象创建自定义验证属性。此属性应该执行某种数据存储查找。例如,我需要我的内容具有独特的slugs。要检查 Slug 是否已存在,我想在 Base 内容对象中使用自定义 DataAnnotation 属性(而不是每次在控制器的插入操作中手动检查 slug 是否存在)。属性逻辑将进行验证。

到目前为止,我已经想出了这个:

public class UniqueSlugAttribute : ValidationAttribute
{
    private readonly IContentRepository _repository;

    public UniqueSlugAttribute(ContentType contentType)
    {
        _repository = new XmlContentRepository(contentType);
    }

    public override bool IsValid(object value)
    {
        if (string.IsNullOrWhiteSpace(value.ToString()))
        {
            return false;
        }

        string slug = value.ToString();
        if(_repository.IsUniqueSlug(slug))
            return true;

        return false;
    }
}

我的基本内容类的一部分:

...
        [DataMember]
        public ContentType ContentType1 { get; set; }

        [DataMember]
        [Required(ErrorMessageResourceType = typeof (Localize), ErrorMessageResourceName = "Validation_SlugIsBlank")]
        [UniqueSlug(ContentType1)]
        public string Slug
        {
            get { return _slug; }
            set
            {
                if (!string.IsNullOrEmpty(value))
                    _slug = Utility.RemoveIllegalCharacters(value);
            }
        }
...

行中有一个错误

    [UniqueSlug(ContentType1)]

说:“属性参数必须是属性参数类型的常量表达式、typeof 表达式或数组创建表达式。”

让我解释一下,我需要向 UniqueSlug 类的构造函数提供 ContentType1 参数,因为我在数据提供程序中使用它。

如果您尝试对内置的必需属性执行此操作,实际上会出现相同的错误:

[Required(ErrorMessageResourceType = typeof (Localize), ErrorMessageResourceName = Resources.Localize.SlugRequired]

它不允许我们将其设置为动态内容。在第一种情况下,ContentType1 在运行时获知,在第二种情况下,Resources.Localize.SlugRequired 也在运行时获知(因为区域性设置是在运行时分配的)。

这真的很烦人,并且使得很多事情和实现场景变得不可能。

所以,我的第一个问题是,如何消除这个错误? 我的第二个问题是,您是否认为我应该以任何方式重新设计我的验证代码?

I have my application designed with Repository pattern implemented and my code prepared for optional dependency injection in future, if we need to support another datastore.

I want to create a custom validation attribute for my content objects. This attribute should perform some kind of datastore lookup. For instance, I need my content to have unique slugs. To check if a Slug already exist, I want to use custom DataAnnotation attribute in my Base content object (instead of manually checking if a slug exists each time in my controller's Insert actions). Attribute logic would do the validation.

So far I have come up with this:

public class UniqueSlugAttribute : ValidationAttribute
{
    private readonly IContentRepository _repository;

    public UniqueSlugAttribute(ContentType contentType)
    {
        _repository = new XmlContentRepository(contentType);
    }

    public override bool IsValid(object value)
    {
        if (string.IsNullOrWhiteSpace(value.ToString()))
        {
            return false;
        }

        string slug = value.ToString();
        if(_repository.IsUniqueSlug(slug))
            return true;

        return false;
    }
}

part of my Base content class:

...
        [DataMember]
        public ContentType ContentType1 { get; set; }

        [DataMember]
        [Required(ErrorMessageResourceType = typeof (Localize), ErrorMessageResourceName = "Validation_SlugIsBlank")]
        [UniqueSlug(ContentType1)]
        public string Slug
        {
            get { return _slug; }
            set
            {
                if (!string.IsNullOrEmpty(value))
                    _slug = Utility.RemoveIllegalCharacters(value);
            }
        }
...

There's an error in line

    [UniqueSlug(ContentType1)]

saying: "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type."

Let me explain that I need to provide the ContentType1 parameter to the Constructor of UniqueSlug class because I use it in my data provider.

It is actually the same error that appears if you try do to this on the built-in Required attribute:

[Required(ErrorMessageResourceType = typeof (Localize), ErrorMessageResourceName = Resources.Localize.SlugRequired]

It does not allow us to set it to dynamic content. In the first case ContentType1 gets known at runtime, in the second case the Resources.Localize.SlugRequired also gets known at runtime (because the Culture settings are assigned at runtime).

This is really annoying and makes so many things and implementation scenarios impossible.

So, my first question is, how to get rid of this error?
The second question I have, is whether you think that I should redesign my validation code in any way?

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

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

发布评论

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

评论(1

清君侧 2024-09-04 06:19:12

消除错误的唯一方法是按照它的说明进行操作,并将静态内容放入属性中。请记住,属性的用途是代码上的元数据,专门用于在运行时查找有关代码的信息。使这种动态变得有悖于这一目的。

在我看来,如果您的 slug 是基于内容类型的动态,那么 Slug 属性应该是使用内容类型初始化的对象。从发布的属性代码来看,无论如何都不需要在构造函数中初始化存储库 - 因此将其移至 IsValid() 方法并在其中执行所有操作,只需进行一些检查以确保该值转换为 Slug 并且设置了 ContentType 属性。

如果您需要围绕属性进行大量动态实现场景,这可能表明存在设计问题。

The only way to get rid of the error is to do what it says, and put static content in your attributes. Remember that the purpose of attributes is for metadata on your code that is specifically for the purposes of looking up information about your code at runtime. Making this dynamic would defeat this purpose.

It seems to me that if your slug is dynamic based on the content type, then the Slug property should be an object that is initialized with the content type. From the attribute code posted, there's no need to initialize your repository in the constructor anyway - so move it to the IsValid() method and do everything in there, and just do a bit of checking to make sure the the value casts to a Slug and that the ContentType property is set.

If you need to be doing a ton of dynamic implementation scenarios around attributes, this could be indicative of a design problem.

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