5

ASP.net MVC 3 プロジェクトで Fluent Validation フレームワークを使用しています。これまでのところ、すべての検証は非常に単純でした (文字列が空でないこと、特定の長さだけであることなど) ですが、データベースに何かが存在するかどうかを確認する必要があります。

  1. この場合、Fluent Validation を使用する必要がありますか?
  2. Fluent Validation を使用してデータベースの検証を行う必要がある場合、依存関係をどのように処理すればよいですか? バリデータ クラスは自動的に作成されます。データベースにクエリを実行するには、何らかの方法でリポジトリ インスタンスの 1 つを渡す必要があります。

私が検証しようとしているものの例は次のとおりです。

ページに、選択した項目のリストを含むドロップダウン リストがあります。新しいレコードを保存する前に、選択した項目が実際にデータベースに存在することを確認したいと考えています。

編集
Fluent Validation フレームワークでの通常の検証のコード例を次に示します。

[Validator(typeof(CreateProductViewModelValidator))]
public class CreateProductViewModel
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class CreateProductViewModelValidator : AbstractValidator<CreateProductViewModel>
{
    public CreateProductViewModelValidator()
    {
        RuleFor(m => m.Name).NotEmpty();
    }
}

コントローラ:

public ActionResult Create(CreateProductViewModel model)
{
    if(!ModelState.IsValid)
    {
        return View(model);
    }

    var product = new Product { Name = model.Name, Price = model.Price };
    repository.AddProduct(product);

    return RedirectToAction("Index");
}

ご覧のとおり、私は Validator を自分で作成することはありません。これは、 の次の行により機能しますGlobal.asax

FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure();

問題は、リポジトリを使用してデータベースとやり取りする必要があるバリデーターができたことですが、バリデーターを作成していないため、具体的な型をハードコーディングする以外に、その依存関係を渡す方法がわかりません。

4

5 に答える 5

1

このリンクは、モデルを手動でインスタンス化して手動で検証することなく、探しているものを実装するのに役立ちます。このリンクは、FluentValidation ディスカッション フォーラムから直接提供されています。

于 2011-12-08T15:11:55.683 に答える
0

これが機能するもう1つの方法は、コンストラクターインジェクションを使用することです。この方法は、IoCライブラリを使用するほど明確ではありませんが、セッションにアクセスまたはフェッチする静的な方法がある場合に役立つことがあります。

public class CreateProductViewModelValidator
{
    private ISession _session;

    public CreateProductViewModelValidator()
        :this(SessionFactory.GetCurrentSession()) //Or some other way of fetching the repository.
    {

    }

    internal CreateProductViewModelValidator(ISession session)
    {
        this._session = session;
        RuleFor(m => m.Name);//More validation here using ISession...
    }
}
于 2011-12-09T04:32:20.863 に答える
0

私はこれとまったく同じ問題について考えるのにかなりの時間を費やしてきました。ninject を使用してリポジトリを Web UI レイヤーに挿入し、Web UI がインターフェイスを介してのみデータベースにアクセスできるようにしています。

重複した名前のチェックなど、データベースにアクセスするものを検証できるようにしたいので、検証では注入されたリポジトリにアクセスする必要があります。これを行う最善の方法は、MVC 統合された方法ではなく、手動の方法で Fluent Validation をセットアップすることだと思います。例えば:

検証クラスを作成します (リポジトリ インターフェイスで渡すことができます)。

public class CategoryDataBaseValidation : AbstractValidator<CategoryViewModel>
{

    private IRepository repository;

    public CategoryDataBaseValidation (IRepository repoParam) 
    {

        repository = repoParam;

        RuleFor(Category => Category.Name).Must(NotHaveDuplicateName).WithMessage("Name already exists");
    }

    private bool NotHaveDuplicateName(string name) 
    {

       List<Category> c = repository.Categories.ToList(); //Just showing that you can access DB here and do what you like.
       return false;


    }
}

}

次に、コントローラーで上記のクラスのインスタンスを作成し、リポジトリに渡すことができます(そのninjectはコントローラーコンストラクターに注入されます)

 [HttpPost]
    public ActionResult Create(CategoryViewModel _CategoryViewModel )
    {

        CategoryDataBaseValidation validator = new CategoryDataBaseValidation (repository);

        ValidationResult results = validator.Validate(_CategoryViewModel );

       if (results.IsValid == false)
        {

            foreach (var failure in results.Errors)
            {

              //output error

            }

        }

        return View(category);
    }

上記のファイルは両方とも Web UI プロジェクトに置くことができ、クライアント側の検証に標準の MVC DataAnnotations を使用することもできます。

コメントのためにこれを投稿する/誰かを助けると思っただけです。

于 2013-05-02T00:44:23.163 に答える
0

データベースの検証を開始する独自の検証方法を作成することはできませんか?

    RuleFor(m => m.name)
           .Must(BeInDatabase)

    private static bool BeInDatabase(string name)
    {
        // Do database validation and return false if not valid
        return false;
    }
于 2011-12-08T10:14:49.277 に答える
0

データベースの検証に FluentValidation を使用しています。Validation クラスを Ctor のセッションに渡すだけです。アクション内で次のような検証を行います。

var validationResult = new ProdcutValidator(session).Validate(product);

更新:あなたの例に基づいて、私の例を追加します...

public class CreateProductViewModel
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
    private readonly ISession _session;
    public CreateProductViewModelValidator(ISession session)
    {
        _session = session;
        RuleFor(m => m.Name).NotEmpty();
        RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);

    }
}
Controller:

public ActionResult Create(CreateProductViewModel model)
{
    var validator = new CreateProductViewModelValidator();
    var validationResult =validator.Validate(model);

    if(!validationResult.IsValid)
    {
        // You will have to add the errors by hand to the ModelState's errors so the
        // user will be able to know why the post didn't succeeded(It's better writing 
        // a global function(in your "base controller" That Derived From Controller)
        // that migrate the validation result to the 
        // ModelState so you could use the ModelState Only.
        return View(model);
    }

    var product = new Product { Name = model.Name, Price = model.Price };
    repository.AddProduct(product);

    return RedirectToAction("Index");
}

2 番目の更新:
パラメーターなしのコンストラクターの使用を主張する場合は、オブジェクトの Factory のような静的クラスであるInversion Of control containerを使用する必要があります。次のように使用します。

public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
    private readonly ISession _session;
    public CreateProductViewModelValidator()
    {
        _session = IoC.Container.Reslove<ISession>();
        RuleFor(m => m.Name).NotEmpty();
        RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);

    }
}

多くの IoC コンテナを見つけることができます。最も有名なのはWindsorNinjectです。すべての ISession を解決して自分のセッション オブジェクトを返すようにコンテナに登録する必要があります。

于 2011-11-29T21:48:12.017 に答える