自定义 DataAnnotation 和依赖关系注入

Custom DataAnnotation and Dependency Injection

提问人:Sagar Tube 提问时间:9/3/2023 更新时间:9/3/2023 访问量:35

问:

我有 2 个模型类 Batch 和 Coach,如下所示

批处理 .cs

public class Batch
  {
    public int Id { get; set; }

    public string Name { get; set; }

     [NoBatchAfter9PM]
     public TimeSpan StartTime { get; set; }

     [NoBatchAfter9PM]
     public TimeSpan EndTime { get; set; }

     public string? Description { get; set; }

     [Display(Name="Is it a Weekend batch?")]
     public bool IsWeekendBatch { get; set; }

     [Display(Name = "Is it a Womens batch?")]
     public bool IsWomenBatch { get; set; }

     public ICollection<Learner>? Learners { get; set; }

     public Coach? Coach { get; set; }
}

教练 .cs

public class Coach
{
   public int Id { get; set; }

   public string Name { get; set; }

   [Display(Name="Gender")]
   public GenderId GenderId { get; set; }

   [Display(Name = "Batch")]
   public int BatchId { get; set; }

   [ForeignKey("BatchId")]
   public Batch Batch { get; set; }

   [ForeignKey("GenderId")]
   public Gender Gender { get; set; }
}

他们都有一对多的关系。

在 CoachForm 中,我有一个批处理字段的下拉列表。提交表单时 我必须检查教练的性别,如果性别是女性,而批次是女性批次,那么只有 ModelValidation 才能成功,我为此创建了一个自定义 DataAnnotation,如下所示。

public class CheckForGenderAndBatch:ValidationAttribute
    {
        IBatchRepository batchRepository;
        static List<Batch> WomensBatch;

        public CheckForGenderAndBatch(IBatchRepository batchRepository)
        {
            this.batchRepository = batchRepository;
            WomensBatch = batchRepository.GetBatches().Where(x => x.IsWomenBatch).ToList();
        }
        protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
        {
            Coach coach = (Coach)validationContext.ObjectInstance;

            if (coach.GenderId == GenderId.Male && WomensBatch.Any(x => x.Id == coach.BatchId))
           {
            return new ValidationResult("Only Female Coach is allowed in womens batch");
           }
        return ValidationResult.Success;
         }
    }

对于 IBatchRepository 接口,我已经注册了一个具体类,如下所示 Program.cs

builder.Services.AddTransient<IBatchRepository, BatchProjectDbRepository>();

当我在 Coach.cs 中的属性 BatchId 顶部添加属性时,如下所示,我收到以下错误。

enter image description here

我知道自定义数据注释中没有默认构造函数,因此我尝试传递 Repository 类的引用,如下所示。

[CheckForGenderAndBatch(new BatchProjectDbRepository())]
[Display(Name = "Batch")]
public int BatchId { get; set; }

但这里的问题是,即使是 BatchProjectDbRepository 类也没有默认构造函数。BatchProjectDbRepository 类的结构如下所示。

ProjectDbContext context;
 public BatchProjectDbRepository(ProjectDbContext context)
 {
    this.context = context;
 }  

因此,考虑将 ProjectDbContext 对象传递给它,如下所示。

[CheckForGenderAndBatch(new BatchProjectDbRepository(new ProjectDbContext()))]
[Display(Name = "Batch")]
public int BatchId { get; set; }

但是由于 ProjectDbContext 类构造函数也需要一个参数,因此我收到以下错误enter image description here

所以我的问题是,无论如何,我们是否可以将具体类的对象注入到自定义数据注释的类中?

(很抱歉以如此冗长的方式定义问题)

C# asp.net ASP.Net-Core 验证 依赖项注入

评论


答:

1赞 IbraHim M. Nada 9/3/2023 #1

我明白你想做什么。 无需使用构造函数注入服务。

您必须在运行时使用对象和方法获取实现ValidationContextGetService

-步骤

1-使你的验证器类的承包商无参数。CheckForGenderAndBatch

2-内使用这条线IsValid

var batchRepository = (IBatchRepository ) validationContext.GetService(typeof(IBatchRepository ));

现在,可以通过对象来使用存储库。batchRepository

还有一件事:始终将您的存储库声明为 DI 容器内的范围。

旁注在这种情况下,构造函数用于获取与验证域相关的更多数据,例如,假设您正在尝试验证余额阈值,然后在构造函数中发送所需的阈值值,使验证器尽可能可用。

另一个示例是在构造函数中发送的长度验证,即字符串应超过的长度值,例如 150 个字符。

祝你好运