Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added IServiceProvider to DataAnnotationsValidator #39445

Merged

Conversation

MariovanZeist
Copy link
Contributor

@MariovanZeist MariovanZeist commented Jan 11, 2022

Added DI to ValidationContext

This PR adds the ability to use Dependency Injection in a ValidationAttribute when using the default <DataAnnotationsValidator>

Implemented by adding an overload to the extension methods to remain binary and source compatible.
This method can also be used by other custom validators
closes: #39382

@MariovanZeist MariovanZeist requested a review from a team as a code owner January 11, 2022 22:56
@ghost ghost added area-blazor Includes: Blazor, Razor Components community-contribution Indicates that the PR has been added by a community member labels Jan 11, 2022
@MariovanZeist
Copy link
Contributor Author

Although not a question on the original issue, I could trivially add the IDictionary<object, object?>? items
As an additional overload to the EditContextDataAnnotationsExtensions class so external Validators can use it.
And it could be added as a [Parameter] to the <DataAnnotationsValidator> so developers can fully support the <ValidationContext> out of the box.

@TanayParikh
Copy link
Contributor

Thanks @MariovanZeist for the PR. As you pointed out in the original issue:

Looking at the code it shouldn't be too hard to implement, but there could have been good reasons not to, for example, because of the lack of async validation support, it wouldn't be possible to await a call to your server or database, forcing it to be a blocking call, blocking Blazor rendering and resulting in a bad user experience.

may lead to us not being able to take this into the framework. cc/ @pranavkm thoughts on service DI for validations?

@pranavkm
Copy link
Contributor

Actually this is fine. MVC configures this today and it's very likely this was a straight up miss. If you're doing async validation, and/or trying to block by doing sync-over-async in the validator, that's on the user. But no reason the DI container couldn't be present.

@dotnet dotnet deleted a comment from azure-pipelines bot Jan 13, 2022
@SteveSandersonMS
Copy link
Member

Other than the thread about obsoleting the older API, this all looks great to me!

@@ -13,6 +13,8 @@ public class DataAnnotationsValidator : ComponentBase, IDisposable

[CascadingParameter] EditContext? CurrentEditContext { get; set; }

[Inject] private IServiceProvider ServiceProvider { get; set; } = default!;
Copy link
Member

@SteveSandersonMS SteveSandersonMS Jan 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in two minds about the nullability annotation here. I know the only way you can make it null is to use an obsolete API, but existing code may do that, and then newer code will be getting told a lie by the annotation.

Should we keep it as IServiceProvider? until the obsoleted API is actually removed? Is there prior art for how we handle this scenario elsewhere?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see that @pranavkm just suggested marking it as non-nullable, so perhaps that is an established pattern about obsoletion already. Just waiting for a comment from him to confirm.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is a private property and our implementation always expects injected properties to be available. So annotating it as non-nullable seems correct. Does that sound right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're quite right. Sorry for the confusion!

@SteveSandersonMS SteveSandersonMS self-requested a review January 19, 2022 10:25
Copy link
Member

@SteveSandersonMS SteveSandersonMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates, @MariovanZeist!

I'm going to leave this for @pranavkm to merge if he's also happy. My only remaining question for Pranav is about the nullability annotation but I'll leave it with him to decide whether to merge as-is or to tweak that.

@sipi41
Copy link

sipi41 commented Dec 3, 2023

I found a bug in the implementation... Take for example my code that inject the database... when the code runs the first time it creates the object, why is executed again, not sure, but the second time, it returns null throwing an error when checking the db variable... code example:

`public class ConstraintsV2_Require_Resolution : ValidationAttribute
{

    protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
    {            
       var  db = (TSMC_ODS_DbContext)validationContext
                                     .GetService(typeof(TSMC_ODS_DbContext));     
        
        FACT_Constraint_v2 fACT_Constraint_V2 = (FACT_Constraint_v2)validationContext.ObjectInstance;

        if (value == null)
        {                
            // LINE THAT FAILS... SAYS db IS NULL... but first time it works, not sure why second time it fails...
            DIM_STATUS currentStatus = db.Dim_Statuses.FirstOrDefault(f => f.status_guid == fACT_Constraint_V2.status_guid);

            if (currentStatus != null)
            {
                if (currentStatus.status.Contains("COMPLETE", StringComparison.CurrentCultureIgnoreCase))
                {
                    return new ValidationResult("If Status is \"COMPLETE\" a Resolution must be provided.", new List<string>() { validationContext.MemberName });
                }
            }
        }

        return ValidationResult.Success;

    }
}`

@ghost
Copy link

ghost commented Dec 3, 2023

Hi @sipi41. It looks like you just commented on a closed PR. The team will most probably miss it. If you'd like to bring something important up to their attention, consider filing a new issue and add enough details to build context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Can't inject service in ValidationAttribute
6 participants