在两个项目解决方案中放置FluentValidation验证器类的位置

时间:2018-04-21 13:49:15

标签: fluentvalidation

我在一个解决方案中有一个Web项目和一个类库项目。类库项目包含所有非标识数据的模型。我创建了一个验证器类来验证表中的唯一性(类别)。当我将验证器类放入类库项目时,它无法从Web项目访问上下文(RecipeContext)。如果我尝试将验证器类放入Web应用程序,我会收到“类型或命名空间名称”的错误 无法找到CategoryValidator''。

这是CategoryValidator类

namespace Spicy.Entities.Validators
{
    public class CategoryValidator : AbstractValidator<Category>
    {
        public CategoryValidator()
        {
            RuleFor(x => x.Name).NotNull().WithMessage("Category Name is required.").Must(UniqueName).WithMessage("This category name already exists.");
        }

        private bool UniqueName(Category category, string name)
        {
            using (RecipeContext db = new RecipeContext())
            {
                var dbCategory = db.Categories
                                .Where(x => x.Name.ToLower() == name.ToLower())
                                .SingleOrDefault();

                if (dbCategory == null)
                    return true;

                return dbCategory.ID == category.ID;
            }
        }
    }
}

这是类别模型

using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Spicy.Entities
{
    [Validator(typeof(CategoryValidator))]
    public class Category
    {
        public int ID { get; set; }

        [StringLength(20, ErrorMessage = "Category cannot be longer than 20 characters")]
        [Required]

        public string Name { get; set; }

        [Required]
        [DisplayName("User Name")]
        [StringLength(20, ErrorMessage = "User Name cannot be longer than 20 characters")]
        public string UserName { get; set; }

        public virtual ICollection<Recipe> Recipes { get; set; }
    }
}

这是global.asax代码

    public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        FluentValidationModelValidatorProvider.Configure();
    }
}

我应该在哪里放置验证器类,如何解决我遇到的问题?

帮助。

1 个答案:

答案 0 :(得分:1)

  1. 简单的解决方案(不是最好的): 在验证器中注入RecipeContext,放在Web

    • YourCompany.Domain
      • 模型
        • 分类
        • 其他域类
    • YourCompany.Web
      • 数据访问
        • RecipeContext
      • 验证器
        • CategoryValidator
        • 其他验证员
      • 控制器
  2. 代码:

    public class CategoryValidator : AbstractValidator<Category>
    {
        RecipeContext _db;
        public CategoryValidator(RecipeContext db)
        {
            _db = db;
            RuleFor(x => x.Name).NotNull().WithMessage("Category Name is required.").Must(UniqueName).WithMessage("This category name already exists.");
        }
    
    }
    
    1. 与DDD对齐的高级解决方案:

      • YourCompany.Domain(不依赖于db或web)

        • 模型
          • 分类
          • 其他域类
        • 数据访问
          • ICategoryRepository(仅适用于域对象)
          • 其他存储库
        • 验证程序(为了简单起见,但可以在YourCompany.Domain.Validators中,因为它取决于FluentValidation)
          • CategoryValidator(仅依赖于域对象和域服务:例如ICategoryRepository)
      • YourCompany.DataAccess.EF

        • CategoryRepositoryEF(使用EF实现ICategoryRepository)
      • YourCompany.DataAccess.MongoDB(例如)

        • CategoryRepositoryMongo(使用MongoDB实现ICategoryRepository)
      • YourCompany.Web

        • 控制器
        • 启动
    2. 域中的代码:

      public interface ICategoryRepository
      {
          bool ContainsCategory(string name);
          Category GetById(int id);
          // other db methods for example
          IEnumerable<Category> GetAll();
          void Add(Category entity);
      }
      
      public class CategoryValidator : AbstractValidator<Category>
      {
          ICategoryRepository _categoryRepository;
          public CategoryValidator(ICategoryRepository categoryRepository)
          {
              _categoryRepository = categoryRepository;
              RuleFor(x => x.Name).NotNull().WithMessage("Category Name is required.").Must(UniqueName).WithMessage("This category name already exists.");
          }
      
          private bool UniqueName(Category category, string name)
          {
              return !_categoryRepository.Contains(name);
          }
      }
      

      YourCompany.DataAccess.EF中的代码:

      public class CategoryRepositoryEF
      {
          RecipeContext _db;
      
          public CategoryRepository(RecipeContext db)
          {
              _db = db;
          }
      
          bool ContainsCategory(string name)
          {
              using (RecipeContext db = new RecipeContext())
              {
                  var dbCategory = db.Categories
                                  .Where(x => x.Name.ToLower() == name.ToLower())
                                  .SingleOrDefault();
      
                  if (dbCategory == null)
                      return true;
      
                  return dbCategory.ID == category.ID;
              }
          }
      }
      

      网络代码:

      // This method gets called by the runtime. Use this method to add services to the container.
      public void ConfigureServices(IServiceCollection services)
      {
          // Add framework services.
          services.AddDbContext<RecipeContext>(options =>
              options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
      
          // Register application services.
          services.AddScoped<ICategoryRepository, CategoryRepositoryEF>();
      
      }