Code Monkey home page Code Monkey logo

Comments (11)

ryanelian avatar ryanelian commented on June 3, 2024

Interesting. What is this? What does that do? Please elaborate the side effect and use cases of doing that.

That method is also apparently is NOT the built-in method of FluentValidation core library, only the integration library: https://github.com/JeremySkinner/FluentValidation/blob/master/src/FluentValidation.AspNetCore/FluentValidationMvcExtensions.cs#L82


In my code, IServiceProvider is accessible just like any other services because I'm registering the validator into my Dependency Injection.

On Startup.cs

services.AddTransient<IValidator<EditAccountFormModel>, EditAccountFormModelValidator>();

(Example: https://github.com/ryanelian/FluentValidation.Blazor/blob/master/Demo/Startup.cs#L36 registering validator https://github.com/ryanelian/FluentValidation.Blazor/blob/master/Demo/Models/FormModel2.cs#L15-L32 which calls another service as part of the validation logic https://github.com/ryanelian/FluentValidation.Blazor/blob/master/Demo/Services/EmailCheckerService.cs)

Allows you to do this:

image

^ Look at the debugger values

from fluentvalidation.blazor.

Sebazzz avatar Sebazzz commented on June 3, 2024

Interesting. What is this? What does that do?

This allows injecting scope-dependent services in the validator without relying on things like IHttpContextAccessor. This is especially useful if you have a factory for a child validator (especially for things like string).

from fluentvalidation.blazor.

ryanelian avatar ryanelian commented on June 3, 2024

Isn't current method of registering validator to the DI already allowed injecting services to the validator?

My example above doesn't rely on IHttpContextAccessor but INJECTS IServiceProvider and MyDbContext to the validator which then be used to get the IHttpContextAccessor (read again)

Check again:

(Example: https://github.com/ryanelian/FluentValidation.Blazor/blob/master/Demo/Startup.cs#L36 registering validator https://github.com/ryanelian/FluentValidation.Blazor/blob/master/Demo/Models/FormModel2.cs#L15-L32 which calls another service as part of the validation logic https://github.com/ryanelian/FluentValidation.Blazor/blob/master/Demo/Services/EmailCheckerService.cs)

Please give specific code example for your specific use case because I can't understand what you meant.

from fluentvalidation.blazor.

Sebazzz avatar Sebazzz commented on June 3, 2024

There are two IServiceProvider: one global and one which is able to provide per-scope services. Note that a scope in Blazor different as opposed to a scope in regular MVC: Because Blazor is a websockets connection there is a long running scope and no HTTP context.

from fluentvalidation.blazor.

ryanelian avatar ryanelian commented on June 3, 2024

There are two IServiceProvider:

This is the first time I've ever heard of this. Please give reference to the documentation and code examples?

from fluentvalidation.blazor.

Sebazzz avatar Sebazzz commented on June 3, 2024

Try: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.0#request-services

The services available within an ASP.NET Core request from HttpContext are exposed through the HttpContext.RequestServices collection.

Request Services represent the services configured and requested as part of the app. When the objects specify dependencies, these are satisfied by the types found in RequestServices, not ApplicationServices.

Some instances can only be retrieved through the service provider for the specific scope.

If you look at CircuitFactory.CreateCircuitHost you see that at line 44 a new serviceprovider is initiated.

from fluentvalidation.blazor.

ryanelian avatar ryanelian commented on June 3, 2024

Okay...

image

That doesn't explain what you told me about there being two IServiceProvider

I can't find the code you quoted on the page:

image


Anyway, what's stopping you from requesting a service from the validator (like my examples above)? Just give me your service code example so I can work with real example.

from fluentvalidation.blazor.

Sebazzz avatar Sebazzz commented on June 3, 2024

That doesn't explain what you told me about there being two IServiceProvider

One ServiceProvider is scope based and will resolve scope-based services, while the other will not.

I can't find the code you quoted on the page

That is the Blazor source code, check out the 3.0.0 tag on the AspNetCore repository.

As for the validation, take this rule for instance:

       this.RuleFor(e => e.Passphrase).
            InjectValidator((sp, context) =>
            {
                var validatorFactory = sp.GetRequiredService<PassphraseValidatorFactory>();
                MyCommand obj = context.InstanceToValidate;
                return validatorFactory.MakePassphraseValidator(obj.RetroId, obj.JoiningAsManager, obj.Passphrase);
            });

It depends on a PassphraseValidatorFactory which takes a DbContext which is request scoped.

from fluentvalidation.blazor.

ryanelian avatar ryanelian commented on June 3, 2024

As for the validation, take this rule for instance:

Ah, so you're using the CUSTOM MVC validation rule . Not built-in in-the-box rule for FluentValidation.

(https://github.com/JeremySkinner/FluentValidation/blob/master/src/FluentValidation.DependencyInjectionExtensions/DependencyInjectionExtensions.cs#L64
https://github.com/JeremySkinner/FluentValidation/blob/master/src/FluentValidation.DependencyInjectionExtensions/DependencyInjectionExtensions.cs#L84-L109 note that it's in the integration project, not the core FluentValidation project)

Keep in mind, this project is designed to be integrated with the vanilla / core FluentValidation project as a Blazor Component, not as MVC integration library. They are two different beasts.

As for your rule, it's not too hard to rewrite it for my library:

public class SebazzFormValidator : AbstractValidator<SebazzFormModel> 
{
    private readonly SebazzRequiredService MyService;

    public SebazzFormValidator(SebazzRequiredService svc)
    {
        this.MyService = svc;

        RuleFor(e => e.Passphrase).Must(ValidatePassphrase).WithMessage("ErrorWhenValidatingPassPhrase")
    }

    public bool ValidatePassphrase(value)
    {
        // var something = MyService.UseMyMethod(value);
        // etc. etc.
    }
}

As you can see, whatever service / factory you require will be injected through the constructor, as per ASP.NET Core Dependency Injection Best Practice:

image


You can then register the validator in the DI alongside your required service:

services.AddTransient<IValidator<SebazzFormModel>, SebazzFormValidator>();
services.AddTransient<SebazzRequiredService>();

If you need support for scoped validation, use OwningComponentBase class provided by the Blazor framework: https://docs.microsoft.com/en-us/aspnet/core/blazor/dependency-injection?view=aspnetcore-3.0#utility-base-component-classes-to-manage-a-di-scope

Is my above example clear enough?

from fluentvalidation.blazor.

ryanelian avatar ryanelian commented on June 3, 2024

Upon observation, it also might be possible to add support for FluentValidation.DependencyInjectionExtensions although very hacky-in-nature and prone to breaking. Not sure if want to support this:

(The author explicitly wrote Making use of InjectValidator or GetServiceProvider is only supported when using the automatic MVC integration. in the class)

image

Setting Root Context Data _FV_ServiceProvider value to IServiceProvider will allow consumers of FluentValidation.Blazor to use InjectValidator methods.

EDIT

Disregard that, it exploded when attempted.

[2019-10-07T20:47:33.420Z] Error: System.NullReferenceException: Object reference not set to an instance of an object.
   at FluentValidation.DependencyInjectionExtensions.<>c__2`2.<InjectValidator>b__2_0(IServiceProvider s, ValidationContext`1 ctx) in /home/jskinner/code/FluentValidation/src/FluentValidation.DependencyInjectionExtensions/DependencyInjectionExtensions.cs:line 85
   at FluentValidation.DependencyInjectionExtensions.<>c__DisplayClass3_0`2.<InjectValidator>b__0(IValidationContext context) in /home/jskinner/code/FluentValidation/src/FluentValidation.DependencyInjectionExtensions/DependencyInjectionExtensions.cs:line 102
   at FluentValidation.Validators.ChildValidatorAdaptor.GetValidator(PropertyValidatorContext context) in /home/jskinner/code/FluentValidation/src/FluentValidation/Validators/ChildValidatorAdaptor.cs:line 86
   at FluentValidation.Validators.ChildValidatorAdaptor.Validate(PropertyValidatorContext context) in /home/jskinner/code/FluentValidation/src/FluentValidation/Validators/ChildValidatorAdaptor.cs:line 49
   at FluentValidation.Internal.PropertyRule.InvokePropertyValidator(ValidationContext context, IPropertyValidator validator, String propertyName) in /home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:line 423
   at FluentValidation.Internal.PropertyRule.Validate(ValidationContext context)+MoveNext() in /home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:line 282
   at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at FluentValidation.AbstractValidator`1.Validate(ValidationContext`1 context) in /home/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs:line 115
   at FluentValidation.AbstractValidator`1.FluentValidation.IValidator.Validate(ValidationContext context) in /home/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs:line 69
   at FluentValidation.FluentValidator.ValidateModel(EditContext editContext, ValidationMessageStore messages) in D:\VS\FluentValidation.Blazor\FluentValidation.Blazor\FluentValidator.cs:line 97
   at FluentValidation.FluentValidator.<>c__DisplayClass14_0.<AddValidation>b__0(Object sender, ValidationRequestedEventArgs eventArgs) in D:\VS\FluentValidation.Blazor\FluentValidation.Blazor\FluentValidator.cs:line 79
   at Microsoft.AspNetCore.Components.Forms.EditContext.Validate()
   at Microsoft.AspNetCore.Components.Forms.EditForm.HandleSubmitAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)

EDIT 2: Closing this issue, because the goal of this project is to enable Blazor integration against FluentValidation with Dependency Injection / IServiceProvider support; NOT FluentValidation.AspNetCore or FluentValidation.DependencyInjectionExtensions integrations.

from fluentvalidation.blazor.

ryanelian avatar ryanelian commented on June 3, 2024

Added InjectValidator workaround with SetValidator plus standard Dependency Injection to README.

https://github.com/ryanelian/FluentValidation.Blazor#fluentvalidationdependencyinjectionextensions-functions

from fluentvalidation.blazor.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.