双项目解决方案中FluentValidation验证器类的放置位置咨询
解决类库与Web项目间验证器的依赖与访问问题
看起来你掉进了项目依赖和类型访问的典型坑里——我来一步步帮你理清思路、解决问题:
核心问题分析
你的矛盾点本质是项目依赖方向搞反了:Web项目应该引用类库项目(因为类库是共享的模型/工具),但类库项目不能反过来引用Web项目(会造成循环依赖,或者破坏分层架构)。而你需要验证器访问RecipeContext,又不想把验证器放在Web项目里导致其他地方找不到它。
方案一:用依赖注入让类库验证器获取DbContext(推荐)
这是最符合ASP.NET Core设计模式的做法,不需要调整现有项目结构太多:
1. 在类库中编写验证器,通过构造函数注入RecipeContext
假设你用的是FluentValidation(如果是其他验证框架思路类似),修改验证器代码:
using FluentValidation; using YourNamespace.Models; // 你的Category模型所在命名空间 using Microsoft.EntityFrameworkCore; // 必须把类设为public,否则其他项目访问不到 public class CategoryValidator : AbstractValidator<Category> { private readonly RecipeContext _dbContext; // 通过构造函数注入DbContext,而不是直接引用Web项目 public CategoryValidator(RecipeContext dbContext) { _dbContext = dbContext; // 实现唯一性验证逻辑 RuleFor(c => c.Name) .MustAsync(async (name, cancellationToken) => { return !await _dbContext.Categories .AnyAsync(c => c.Name == name, cancellationToken); }) .WithMessage("该分类名称已存在"); } }
2. 在Web项目中注册验证器与DbContext
在Program.cs(或旧版的Startup.cs)中完成依赖注入配置:
// 先注册你的DbContext builder.Services.AddDbContext<RecipeContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // 注册验证器(自动扫描类库中的验证器) builder.Services.AddValidatorsFromAssembly(typeof(CategoryValidator).Assembly);
方案二:把DbContext移到共享数据类库
如果觉得依赖注入的方式有点绕,可以调整项目结构,让DbContext成为共享资源:
- 新建一个数据访问类库项目(比如
YourProject.Data),把Web项目中的RecipeContext移到这里,并确保RecipeContext是public类。 - 让你的模型类库和Web项目都引用这个数据访问类库。
- 把
CategoryValidator放回模型类库,现在它可以直接访问RecipeContext了:
public class CategoryValidator : AbstractValidator<Category> { public CategoryValidator() { RuleFor(c => c.Name) .MustAsync(async (name, cancellationToken) => { // 这里也推荐用依赖注入,而不是直接new DbContext,方便后续测试 using var dbContext = new RecipeContext(); return !await dbContext.Categories.AnyAsync(c => c.Name == name, cancellationToken); }) .WithMessage("该分类名称已存在"); } }
解决“找不到CategoryValidator”的小细节
如果你之前把验证器放在Web项目时出现这个错误,大概率是这两个原因:
- 验证器的访问修饰符是默认的
internal,改成public就能被其他项目访问了。 - 使用验证器的项目没有引用正确的命名空间,记得在需要的地方加
using YourNamespace.Web.Validators;(替换成你的实际命名空间)。
内容的提问来源于stack exchange,提问作者Kim
相关产品推荐
相关产品推荐

