3

FluentValidation の MVC4 統合と Ninject Validator Factory 統合を使用しているときに、1 つのバリデーターのコンテキストをコレクションバリデーターに渡す方法を知っている人はいますか?

例:

public class Foo
{
    public IEnumerable<Bar> Bars { get; set; } 
}

public class Bar
{
    public string Bizz { get; set; }
}

public class FooValidator : AbstractValidator<Foo>
{

    public FooValidator()
    {
        // TODO: send context instance (Foo object) to each BarValidator?
        RuleFor(f => f.Bars).SetCollectionValidator(new BarValidator(/* my context instance here */ ));
    }
}

public class BarValidator : AbstractValidator<Bar>
{
    private IEnumerable<Bar> BarList { get; set; }

    public BarValidator(){ /* this is what the validator factory currently uses but i want to use the one that passes the fooInstance some how */ }

    public BarValidator(Foo fooInstance)
    {
        BarList = fooInstance.Bars.Where(b => b != null).ToList();

        // some function here to validate the Bizz property based on other Bar objects in the BarList collection
        RuleFor(f => f.Bizz).NotEmpty()/* .SomeBizzSiblingFunction() */;

    }
}

このNinject Validator Factoryを使用しているとき

public class NinjectValidatorFactory : ValidatorFactoryBase
{
    /// <summary>
    /// Initializes a new instance of the <see cref="NinjectValidatorFactory"/> class.
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    public NinjectValidatorFactory(IKernel kernel)
    {
        Kernel = kernel;
    }

    /// <summary>
    /// Gets or sets the kernel.
    /// </summary>
    /// <value>The kernel.</value>
    public IKernel Kernel { get; set; }

    /// <summary>
    /// Creates an instance of a validator with the given type using ninject.
    /// </summary>
    /// <param name="validatorType">Type of the validator.</param>
    /// <returns>The newly created validator</returns>
    public override IValidator CreateInstance(Type validatorType)
    {
        if (((IList<IBinding>)Kernel.GetBindings(validatorType)).Count == 0)
        {
            return null;
        }

        return Kernel.Get(validatorType) as IValidator;
    }
}

関連するバリデータ ファクトリを MVC ModelValidatorProviders に追加してバインドします。

ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(new NinjectValidatorFactory(kernel)));

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

AssemblyScanner.FindValidatorsInAssemblyContaining<FooValidator>()
                            .ForEach(match => kernel.Bind(match.InterfaceType).To(match.ValidatorType).InRequestScope());

したがって、最終的にはコントローラーでこのように使用できるため、毎回バリデーターを新しくする必要はありません..しかし、検証時に関連するコンテキストインスタンスも渡す必要があります。

public class FooController : Controller {
    public ActionResult Create() {
        return View();
    }

    [HttpPost]
    public ActionResult Create(Foo foo) {

        if(! ModelState.IsValid) { // re-render the view when validation failed.
            return View("Create", foo);
        }

        return RedirectToAction("Index");

    }
}
4

1 に答える 1

3

私はそれを行うことができる方法を見つけました。以下を参照してください。

public class FooValidator : AbstractValidator<Foo>, IValidatorInterceptor   
{

    public FooValidator() { }

    public ValidationContext BeforeMvcValidation(ControllerContext controllerContext, ValidationContext validationContext)
    {
        RuleFor(f => f.Bar).SetCollectionValidator(new BarValidator(validationContext.InstanceToValidate as Foo));

        return validationContext;
    }

    public ValidationResult AfterMvcValidation(ControllerContext controllerContext, ValidationContext validationContext, ValidationResult result)
    {
        return result;
    }
}

Validator Interceptor を使用し、コンストラクターではなく BeforeMvcValidation メソッドでルールを適用します。また、検証コンテキスト インスタンスを BarValidator に渡します。

于 2013-04-06T20:03:51.223 に答える