如何使用 entlib(或 DataAnnotations)、MVC 和存储库模式执行重复密钥验证

发布于 2024-10-09 11:38:37 字数 1246 浏览 0 评论 0原文

我有一组 ASP.NET 4 项目,最终形成了一个 MVC (3 RC2) 应用程序。该解决方案使用 Unity 和 EntLib Validation 进行横切依赖项注入和验证。两者都非常适合注入存储库和服务层实现。

但是,我不知道如何进行重复密钥验证。例如,当用户注册时,我们希望确保他们不会选择其他人已经在使用的 UserID。对于这种类型的验证,验证对象必须具有存储库引用...或某种其他方式来获取 IQueryable / IEnumerable 引用以检查数据库中已有的其他行。

我拥有的是一个 UserMetadata 类,它包含用户的所有属性 setter 和 getter,以及所有适当的 DataAnnotations 和 EntLib Validation 属性。还有一个使用 EF4 POCO 实体生成器模板实现的 UserEntity 类。 UserEntity 依赖于 UserMetadata,因为它具有 MetadataTypeAttribute。我还有一个 UserViewModel 类,它具有完全相同的 MetadataType 属性。这样,我可以通过属性将相同的验证规则应用于实体和视图模型。

没有对存储库类的具体引用。所有存储库均使用 Unity 注入。还有一个获取依赖注入的服务层。在MVC项目中,服务层实现类被注入到Controller类中(控制器类只包含服务层接口引用)。然后,Unity 将存储库实现注入到服务层类中(服务类也只包含接口引用)。

我已经在元数据类中尝试了 DataAnnotations CustomValidationAttribute。这样做的问题是验证方法必须是静态的,并且该方法不能直接实例化存储库实现。我的存储库接口是 IRepository,并且我只有一个定义为 EntityRepository的存储库实现类。对于所有域对象。要显式实例化存储库,我需要使用 new EntityRepository(),这将导致循环依赖图:UserMetadata [取决于] DuplicateUserIDValidator [取决于] UserEntity [取决于] UserMetadata。

我还尝试创建自定义 EntLib Validator以及自定义验证属性。在这里,我对静态方法没有同样的问题。我想如果我能弄清楚如何让 Unity 将我的 EntityRepository 注入到验证器类中,我就可以让它工作......但我做不到。现在,所有验证代码都在我的元数据类库中,因为那是自定义验证属性所在的位置。

关于如何执行需要检查当前存储库状态的验证有什么想法吗? Unity可以用来将依赖注入到下层类库中吗?

I have a set of ASP.NET 4 projects that culminate in an MVC (3 RC2) app. The solution uses Unity and EntLib Validation for cross-cutting dependency injection and validation. Both are working great for injecting repository and service layer implementations.

However, I can't figure out how to do duplicate key validation. For example, when a user registers, we want to make sure they don't pick a UserID that someone else is already using. For this type of validation, the validating object must have a repository reference... or some other way to get an IQueryable / IEnumerable reference to check against other rows already in the DB.

What I have is a UserMetadata class that has all of the property setters and getters for a user, along with all of the appropriate DataAnnotations and EntLib Validation attributes. There is also a UserEntity class implemented using EF4 POCO Entity Generator templates. The UserEntity depends on UserMetadata, because it has a MetadataTypeAttribute. I also have a UserViewModel class that has the same exact MetadataType attribute. This way, I can apply the same validation rules, via attributes, to both the entity and viewmodel.

There are no concrete references to the Repository classes whatsoever. All repositories are injected using Unity. There is also a service layer that gets dependency injection. In the MVC project, service layer implementation classes are injected into the Controller classes (the controller classes only contain service layer interface references). Unity then injects the Repository implementations into the service layer classes (service classes also only contain interface references).

I've experimented with the DataAnnotations CustomValidationAttribute in the metadata class. The problem with this is the validation method must be static, and the method cannot instantiate a repository implementation directly. My repository interface is IRepository<T>, and I have only one single repository implementation class defined as EntityRepository<T> for all domain objects. To instantiate a repository explicitly I would need to say new EntityRepository<UserEntity>(), which would result in a circular dependency graph: UserMetadata [depends on] DuplicateUserIDValidator [depends on] UserEntity [depends on] UserMetadata.

I've also tried creating a custom EntLib Validator<T> along with a custom validation attribute. Here I don't have the same problem with a static method. I think I could get this to work if I could just figure out how to make Unity inject my EntityRepository into the validator class... which I can't. Right now, all of the validation code is in my Metadata class library, since that's where the custom validation attribute would go.

Any ideas on how to perform validations that need to check against the current repository state? Can Unity be used to inject a dependency into a lower-layer class library?

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

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

发布评论

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

评论(3

月下客 2024-10-16 11:38:37

在数据库中进行。这是唯一真正实现多用户安全的解决方案。

Do it in the database. That's the only solution which can be truly multi-user safe.

哽咽笑 2024-10-16 11:38:37

我找到了一个解决方案,但仍然不确定它是否是最好的。对我来说似乎有点像蛮力。

我做的第一件事是将我的元数据类合并到与我的实体类相同的项目/库中。由于我的存储库接口是 IRepository,因此需要将存储库声明为 IRepository。这解决了我所说的循环依赖。现在我有 UserEntity [取决于] UserMetadata [取决于] DuplicateUserValidationAttribute [取决于] DuplicateUserValidator [取决于] UserEntity。由于所有这些类都位于同一个库中,尽管仍然存在循环性,但不存在循环程序集依赖关系。

我做的第二件事是将 IUnityContainer 包装到一个单例中,并将其移至我的横切实用程序库(之前它仅存在于 MVC 3 项目中)。

然后,在我的 DuplicateUserValidator 构造函数中,我可以执行以下操作:

public class DuplicateUserValidator : Micrsoft.Practices.EnterpriseLibrary.Validation.Validator<string>
{
    public IRepository<UserEntity> UserRepository { get; set; }

    public DuplicateUserValidator(string tag)
        : base(string.Empty, tag)
    {
        IUnityContainer unity = UnityContainerSingleton.Get();
        this.UserRepository = unity.Resolve<IRepository<UserEntity>>() as IRepository<UserEntity>;
    }
}

现在,我将存储库依赖项注入到自定义 entlib 验证器实现中。希望我能够统一自动将其注入到构造函数中,也许接下来我会研究一下。

I found a solution, still not sure if it's the best one. Seems kind of like brute force to me.

The first thing I did was combine my Metadata classes into the same project / library as my Entity classes. Since my repository interface is IRepository<T>, the repository needed to be declared as IRepository<UserEntity>. This resolved the circular dependency I was talking about. Now I have UserEntity [depends on] UserMetadata [depends on] DuplicateUserValidationAttribute [depends on] DuplicateUserValidator [depends on] UserEntity. With all of these classes in the same library, though there is still circularity, there are no circular assembly dependencies.

The second thing I did was wrap my IUnityContainer into a singleton and moved it to my cross-cutting utilities library (before it existed only in the MVC 3 project).

Then, in my DuplicateUserValidator constructor, I could do the following:

public class DuplicateUserValidator : Micrsoft.Practices.EnterpriseLibrary.Validation.Validator<string>
{
    public IRepository<UserEntity> UserRepository { get; set; }

    public DuplicateUserValidator(string tag)
        : base(string.Empty, tag)
    {
        IUnityContainer unity = UnityContainerSingleton.Get();
        this.UserRepository = unity.Resolve<IRepository<UserEntity>>() as IRepository<UserEntity>;
    }
}

Now I have a repository dependency injected into the custom entlib validator implementation. Wish I could get unity to automatically inject it into the constructor, maybe I'll look into that next.

别念他 2024-10-16 11:38:37

好的,我找到了一个更好的解决方案,可以让我使用以前的库架构。

我能够将 UserMetadata 类保存在与 UserEntity 不同的库中。依赖关系图如下所示:

UserMetadata [depends on] DuplicateUserValidationAttribute [depends on] IDuplicateUserValidator

实际的 DuplicateUserValidator 实现类位于我的服务层中,看起来像这样:

public class DuplicateUserValidator : Validator<string>, IDuplicateUserValidator
{
    public DuplicateUserValidator()
        : base(null, null)
    {
    }

    [Dependency]
    public IRepository<UserEntity> UserRepository { get; set; }

    protected override string DefaultMessageTemplate
    {
        get { throw new NotImplementedException(); }
    }

    protected override void DoValidate(string stringToValidate, object currentTarget, string key, ValidationResults validationResults)
    {
        if (this.UserRepository == null)
            throw new InvalidOperationException("This should not happen");

        // actual code to perform validation...
    }
}

技巧是让 DuplicateUserValidatorAttribute 不依赖于 DuplicateUserValidator:

public class DuplicateUserValidatorAttribute : ValidatorAttribute
{
    protected override Validator DoCreateValidator(Type targetType)
    {
        var validator = Unity.Container.Resolve<IDuplicateUserValidator>() as Validator;
        validator.Tag = Tag;
        validator.MessageTemplate = GetMessageTemplate();
        return validator;
    }

}

All我需要从那里添加一个映射到统一配置。当单例解析 IDuplicateUserValidator 时,它会从服务层注入我的实现类,并遵循 UserRepository 属性上的 [Dependency] 属性。

Okay, I found a better solution that lets me use my previous library architecture.

I was able to keep the UserMetadata class in a separate library from UserEntity. Here is what the dependency graph looks like:

UserMetadata [depends on] DuplicateUserValidationAttribute [depends on] IDuplicateUserValidator

The actual DuplicateUserValidator implementation class is in my service layer, and looks something like this:

public class DuplicateUserValidator : Validator<string>, IDuplicateUserValidator
{
    public DuplicateUserValidator()
        : base(null, null)
    {
    }

    [Dependency]
    public IRepository<UserEntity> UserRepository { get; set; }

    protected override string DefaultMessageTemplate
    {
        get { throw new NotImplementedException(); }
    }

    protected override void DoValidate(string stringToValidate, object currentTarget, string key, ValidationResults validationResults)
    {
        if (this.UserRepository == null)
            throw new InvalidOperationException("This should not happen");

        // actual code to perform validation...
    }
}

The trick is getting the DuplicateUserValidatorAttribute to not depend on DuplicateUserValidator:

public class DuplicateUserValidatorAttribute : ValidatorAttribute
{
    protected override Validator DoCreateValidator(Type targetType)
    {
        var validator = Unity.Container.Resolve<IDuplicateUserValidator>() as Validator;
        validator.Tag = Tag;
        validator.MessageTemplate = GetMessageTemplate();
        return validator;
    }

}

All I needed to do from there was add a mapping to the unity config. When the singleton resolves the IDuplicateUserValidator, it injects my implementation class from the service layer, honoring the [Dependency] attribute on the UserRepository property.

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