GithubHelp home page GithubHelp logo

mrpmorris / blazor-validation Goto Github PK

View Code? Open in Web Editor NEW
194.0 11.0 24.0 326 KB

Validation extensions for Microsoft Blazor / FluentValidation

License: MIT License

C# 57.62% HTML 30.43% CSS 11.95%
blazor validation fluentvalidation microsoft-aspdotnet-blazor blazor-fluentvalidation blazor-validation fluent-validation

blazor-validation's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blazor-validation's Issues

config.AddFluentValidation -> Index was outside the bounds of the array.

When I try to register the validators using AddFluentValidation I get an exception:

System.IndexOutOfRangeException
  HResult=0x80131508
  Message=Index was outside the bounds of the array.
  Source=PeterLeslieMorris.Blazor.FluentValidation
  StackTrace:
   at PeterLeslieMorris.Blazor.Validation.ValidationConfigurationFluentValidationExtensions.ScanForValidators(IServiceCollection services, IEnumerable`1 assembliesToScan)
   at PeterLeslieMorris.Blazor.Validation.ValidationConfigurationFluentValidationExtensions.AddFluentValidation(ValidationConfiguration config, Assembly assemblyToScan, Assembly[] additionalAssembliesToScan)
   at ::redacted::.ConfigurationManagement.Blazor.Startup.<>c.<ConfigureServices>b__4_2(ValidationConfiguration config) in C:\Users\::redacted::\source\repos\Configuration Management Admin Tool\::redacted::.ConfigurationManagement.Blazor\Startup.cs:line 110

image
There's no further information about what exactly went wrong.

This exception started after these validators were added:

   public class CustomerCompleteValidator: CustomerComplexValidator
   {
      public CustomerCompleteValidator(): base()
      {
      }
   }

   public class CustomerComplexValidator: AbstractValidator<CustomerComplexDto>
   {
      public CustomerComplexValidator()
      {

         RuleFor(p => p.Name)
            .NotEmpty();

         RuleFor(p => p.Email)
            .NotEmpty()
            .EmailAddress();

         RuleFor(x => x.PhoneNumber)
            .NotEmpty();
      }
   }

I am unsure whether or not my validator is invalid, or if it's a bug in this package.

I think a fix would be either make it work, or throw a meaningful exception, so the caller knows what's up.

Add specific validators

Is it at all possible to specify validators rather than using reflection to scan assemblies? Doesn't appear to be. Reflection is causing other referenced assemblies to be loaded in to the app domain that are not otherwise used by my blazor app. Thanks.

Add support for FluentValidation RuleSets

From what I can tell, there is no way to use RuleSets in a form. It might make sense to make it so you can set this on the Validate component like:

<Validate RuleSet="Create" />

Add support for .NET 5.0

The following exception is thrown during validation in the client:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Number of parameters specified does not match the expected number.
System.Reflection.TargetParameterCountException: Number of parameters specified does not match the expected number.
   at System.Reflection.RuntimeMethodInfo.ConvertValues(Binder binder, Object[] args, ParameterInfo[] pinfo, CultureInfo culture, BindingFlags invokeAttr)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.NotifyPropertyChanged(EditContext editContext, Object instance, String propertyName)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.ValidateProperty(EditContext editContext, Object instance, PropertyInfo property, HashSet`1 validatedObjects)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.ValidateObject(EditContext editContext, Object instance, HashSet`1 validatedObjects)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.ValidateObjectTree(EditContext editContext)
   at CPCA.WebUI.Client.Pages.ContactInformation.HandleSubmit(EditContext context) in D:\Source\CPCAv4\source\CPCA.WebUI\Client\Pages\ContactInformation.razor.cs:line 40
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.Forms.EditForm.HandleSubmitAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)

This is caused by a dependency on an internal method on the EditContext. In netstandard2.1 the signature is:

internal FieldState GetFieldState(in FieldIdentifier fieldIdentifier, bool ensureExists);

In net5.0 the previous method has been replaced by two new methods:

internal FieldState? GetFieldState(in FieldIdentifier fieldIdentifier);
internal FieldState GetOrAddFieldState(in FieldIdentifier fieldIdentifier);

I'm working on a pull request that addresses this but need guidance on how you would like to proceed. My preference would be a Major Version increment and simply drop support for netstandard2.1 as trying to multi-target both netstandard2.1 and 'net5.0' is a PITA.

How do I validate multiple properties with the same rule, without showing multiple errors?

I have a RenewalViewModel, which is bound to controls that allow a user to set up a renewal for an investment. Investors have a level (basic, business, corporate, etc), and within each level, a monthly amount (£100, £200, etc). These two are bound to a SelectedLevelId and SelectedLevelAmountId properties on the view model. These two are bound to two dropdowns, with the amount dropdown taking its values according to the selected level. In other words, if they choose the basic level, the amounts dropdown gets populated with the amounts for that level. If you change it to business, the amounts dropdown gets repopulated accordingly.

The model also has a List<Shares>, which contains an entry for each share the investor currently has, ie one Share object for each company they have invested in, and the Share object has a Quantity property to say how many shares they have invested in that company.

Each investor has a maximum number of shares they can be allocated, based on the level amount they are on. So, one of the things I need to validate is that the total number of shares they are being allocated does not exceed the maximum they are allowed.

I have set up a validator for this as follows (irrelevant properties removed for clarity)...

    public RenewalViewModelValidator() {
      RuleFor(rvm => rvm.SelectedLevelId).Custom((_, ctx) => ValidateShares(ctx));
      RuleFor(rvm => rvm.SelectedLevelAmountId).Custom((_, ctx) => ValidateShares(ctx));
      RuleFor(rvm => rvm.Shares).Custom((_, ctx) => ValidateShares(ctx));
    }

    private static void ValidateShares(CustomContext ctx) {
      RenewalViewModel rvm = (RenewalViewModel)ctx.InstanceToValidate;
      int investorMaxShares = rvm.LevelAmounts.Single(la => la.Id == rvm.SelectedLevelAmountId).NumberOfShares;
      if (rvm.Shares.Sum(s => s.Quantity) > investorMaxShares) {
        ctx.AddFailure($"The max shares for this investor is {investorMaxShares}");
      }
      foreach (Share share in rvm.Shares) {
        int totalSharesInCompany = share.Quantity + rvm.OtherShares.Where(os => os.CompanyId == share.CompanyId).Sum(os => os.Quantity);
        if (totalSharesInCompany > rvm.MaxSharesPerCompany) {
          ctx.AddFailure($"A total of {totalSharesInCompany} shares is now allocated to {share.Company.FullName}, which is more than the maximum of {rvm.MaxSharesPerCompany}");
        }
      }
    }
  }

As you can see, I pulled out the code that checks the number of shares into a method, so when the level, level amount or any of the share quantities is changed, the validation is fired.

This basically works, but has two problems...

  1. As the validation is triggered from three different properties, I get the validation error three times. I only want each error once.

  2. If you change the level, then the amounts dropdown is repopulated, and the first value selected. The validation is fired for the level, but not for the amount, which can lead to incorrect validation messages. If you then change the amount, the validation fires for that, but not for the level, so you can end up with inconsistent validation messages.

It could be I'm just doing this the wrong way, in which case any advice would be appreciated. If not, is there a way to get all of the validation rules fired when any of these three properties change? That way at least the messages would be correct and consistent, although I'd still end up with duplicates.

Hope that all makes sense. Thanks for any help you can give.

Null reference exception in FluentValidationValidator

Just trying fluent validation, and I copied the sample code from the Blazor University source's CustomValidation project. Other than the namespaces, I copied the following classes verbatim...

Person.cs
PersonValidator.cs
FluentValidationValidator.cs
Index.razor

However, when I run the code and click the Save button, I get a null reference exception on the following line in FluentValidationValidator.ValidationRequested...

ValidationResult result = await Validator.ValidateAsync(validationContext);

Validator is null. Any ideas?

Thanks

Validating IsValueType using ValidateObjectTree

Hi,

I've a struct similar to this:

public string Photo { get; set; }
public string Name { get; set; }
public string Last { get; set; }
public int? InfoInt { get; set; } = null;

On the submit button I've the following code:

void SubmitForm(EditContext editContext)
    {
        editContext.ValidateObjectTree();
    }

When I execute the ValidateObjectTree it doesn't validate the field 'InfoInt' which is 'int?', looking through the source code I found on 'EditContextExtensions.cs' on the 'ValidateProperty' method you check for this:

		if (property.PropertyType.IsValueType)
				return;

This prevent any integer validation, if I comment this out the validation works as planned.

Any special reason for this? Can I safely comment this out? Any help is appreciated.

Thanks

Validator for base interface

Hi Peter.
I'm trying to use this library, but I have a validator for a base interface and two different implementation classes, so that my situation is something like:

public class MyValidator : AbstractValidator<IBaseInterface> {...}

And then I have two 'validatable' classes like in:

public class A : IBaseInterface {...}
public class B : IBaseInterface {...}

I think that the automatic discovery you implemented in this library records only the direct types, so when I have a Blazor form based on an instance of class A, for example, I see that validation doesn't automatically kick in.
I would like to have the possibility to register manually custom behaviors like this case, something like:

builder.Services.RegisterValidator<A, MyValidator>();
builder.Services.RegisterValidator<B, MyValidator>();

...unless I have some other error that I don't see, of course... :-)

Thank you (again :-) )
Andrea

Nested RuleForEach: GetParentObjectAndPropertyName fails to find the PropertyInfo

public class DemographicValidator : AbstractValidator<AppContext>
{
    public DemographicValidator() 
    {
        RuleForEach(x => x.Assignments).ChildRules(x =>
        {
            x.RuleForEach(x => x.StaffHistory).ChildRules(x =>
            {
                x.RuleFor(x => x.StartDate).NotEmpty().WithMessage("Start Date is required.");
            });
        }
    }
}

I've omitted most of the rest of the validation for brevity, as that all worked without issue until this one. Once it gets here it throws a null reference error when trying to get property.GetValue(model, null) because property is null.

private void GetParentObjectAndPropertyName(object model, string propertyPath, out object parentObject, out string propertyName)
{
	if (model == null)
	{
		throw new ArgumentNullException("model");
	}
	Queue<string> queue = new Queue<string>(propertyPath.Split('.'));
	Type type = model.GetType();
	while (queue.Count > 1)
	{
		string text = queue.Dequeue();
		string text2 = null;
		int num = text.IndexOf('[');
		if (num > 0)
		{
			text2 = text.Substring(num + 1, text.Length - num - 2);
			text = text.Remove(num);
		}
		PropertyInfo property = type.GetProperty(text);
		model = ((model == null) ? null : property.GetValue(model, null));
		if (text2 == null)
		{
			type = property.PropertyType;
			continue;
		}
		List<object> list = ((IEnumerable<object>)model).ToList();
		int index = int.Parse(text2);
		model = list[index];
	}
	parentObject = model;
	propertyName = queue.Dequeue();
}

It looks like it's trying to get AppContext.StaffHistory instead of Assignment.StaffHistory.

Question

Hi,
I discovered your project because I read dotnet/aspnetcore#23380

Currently DataAnnotations in Blazor do not support IStringLocalizer, so I tried to extend attributes, but I read there "Injecting services for validation is not a feature Blazor offers."

So I have a question:

despite localization not using IStringLocalizer, DataAnnotations are working in Blazor, so I do not understand the purpose of https://github.com/mrpmorris/blazor-validation/tree/master/samples/01-DataAnnotationsValidation/

Thanks

Dead Links

Hello :)
The links to the example projects seems to give a 404 for me.

Superfluous validation messages being shown

I have a validator that contains the following rule...

RuleFor(a => a.Email).NotEmpty().EmailAddress();

If I leave the email empty, then the validator shows both messages...

'Email' must not be empty.
'Email' is not a valid email address.

Can we have it show only the one? I would have expected it to show just the first message if the email was empty, and only show the second if it was non-empty, but invalid.

Thanks

Exception thrown when combining blazor-validation with radzen blazor dropdown component

Hi Peter, thank for making this library. I've been enjoying it but I have encountered a weird issue.
I've been combining your validation with some components from Radzen.

I want to mention that I believe that this isn't an issue with your lib exactly but I've been trying to get to bottom of this issue for some time and you might be my best chance, for engineering's sake :D You as an author of the library might be able to point me what's exactly going on, actually I believe you might be of the few people that might get what I am actually talking about at all.

I've raised the issue with the radzen team here: https://forum.radzen.com/t/radzendropdown-and-fluentvalidation-issues/2832 but they seem to be clueless. I'm giving the link so I don't write the same thing twice.

If you have some spare time please take a look. I'd really appreciate it.

Is it possible to use make fluent validation async ?

Hello, I'm looking at the samples and in the Fluent Validation sample the validation is triggered using editContext.ValidateObjectTree();
Is it possible to validate asynchronously and await on it?
The reason is that I need to retrieve some information from the database to validate the object.

Is there a way to ignore a property?

I have created a custom FileUpload component for my project, which is essentially just a Blazor InputFile in a component and I've styled it and added a few other features onchange.

It works absolutely fine / as expected on standard DataAnnotation validated forms. But as soon as I call editContext.ValidateObjectTree() on submit I get this error message?

blazor.server.js:19 [2021-01-21T15:58:52.610Z] Error: System.ArgumentException: The model must be a reference-typed object. (Parameter 'model')
   at Microsoft.AspNetCore.Components.Forms.FieldIdentifier..ctor(Object model, String fieldName)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.NotifyPropertyChanged(EditContext editContext, Object instance, String propertyName)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.ValidateObject(EditContext editContext, Object instance, HashSet`1 validatedObjects)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.ValidateObject(EditContext editContext, Object instance, HashSet`1 validatedObjects)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.ValidateObject(EditContext editContext, Object instance, HashSet`1 validatedObjects)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.ValidateObject(EditContext editContext, Object instance, HashSet`1 validatedObjects)
   at PeterLeslieMorris.Blazor.Validation.Extensions.EditContextExtensions.ValidateObjectTree(EditContext editContext)
   at Gab.Web.Pages.Account.Manage.UserProfile.HandleSubmit(EditContext editContext) in C:\Users\lee\Documents\Projects\Gab\Src\Gab.Web\Pages\Account\Manage\UserProfile.razor.cs:line 52
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__140_0(Object state)
   at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteSynchronously(TaskCompletionSource`1 completion, SendOrPostCallback d, Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteBackground(WorkItem item)

Is there an option or attribute to get your package to ignore this property (Model/Property is either an IBrowserFile or List<IBrowserFile> just like for a standard InputFile)?

Support RuleForEach / ChildRules

FluentValidation returns a field path rather than a fieldname for the following validation scenario. Change provider to cater for this (object + property name).

  public class FormRecordViewModelValidator : AbstractValidator<FormRecord>
  {
      public FormRecordViewModelValidator()
      {
          RuleForEach(m => m.Fields).ChildRules(f =>
          {
              f.RuleFor(v => v.Value).NotEmpty();
              f.RuleFor(v => v.Value).MaximumLength(5);
          });
      }
  }

Can't run the samples, error signing output with public key

I just downloaded the source to look at the samples, but when I try to run, I get the following build error...

Severity Code Description Project File Line Suppression State
Error CS7027 Error signing output with public key from file 'MrPMorris.snk' -- File not found. PeterLeslieMorris.Blazor.Validation (netstandard2.1) D:\blazor-validation-master\src\PeterLeslieMorris.Blazor.Validation\CSC 1 Active

Anyone able to advise? Thanks

Error when Remove item of list child

Hi Team,
I have a error.
I have a list of modal.
Step 1: Add an item (not valid by antotation) to list on front end
Step 2: Click save and run editContext.ValidateObjectTree() return false -> OK show error to front end
Step 3: Then I remove this item
Step 4: Click save and editContext.ValidateObjectTree()
But this return false and error
When i get editContext.GetValidationMessages() This return msg error of deleted item
Please help me fix it

Address validation not working

Thanks for this great tool.
In the example projects, when I click submit, the addresses don't show any validation errors, am I missing something?
Thanks

ConfigurationExtension does not actually build a list of validators associated with a model.

If I understand your code correctly, one of the purposes of the ValidationConfigurationFluentValidationExtensions is to determine ALL the types of validators that associated with particular entity Type. You are storing the associated Validator Types in a List but from what I can tell, your code will only identify one Validator Type, the one associated with the entity model itself, but none of the validators that might be associated with the entity model's properties.

I think that you have to walk the object graph to get all the validators involved.

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.