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

CompareAttribute.IsValid results in null ref #42490

Closed
glararan opened this issue Jun 9, 2020 · 9 comments · Fixed by #110647
Closed

CompareAttribute.IsValid results in null ref #42490

glararan opened this issue Jun 9, 2020 · 9 comments · Fixed by #110647
Labels
area-System.ComponentModel.DataAnnotations in-pr There is an active PR which will close this issue when it is merged
Milestone

Comments

@glararan
Copy link

glararan commented Jun 9, 2020

var compareAttribute = new CompareAttribute("Test");
compareAttribute.IsValid("foo");

Stack trace:

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at System.ComponentModel.DataAnnotations.CompareAttribute.IsValid(Object value, ValidationContext validationContext)
   at System.ComponentModel.DataAnnotations.ValidationAttribute.IsValid(Object value)

Describe the bug

I have multiple models however each model which contains Password/ConfirmPassword cause crash after setting ConfirmPassword. (EDIT: I found out its caused by CompareProperty attribute)

To Reproduce

I implemented my own ValidationContext class which validates on field changed (EditContext) all attributes per changing field.

Implementation of ValidationContext for OnFieldChanged looks like this:

void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
{
    PropertyInfo property = Model.GetType().GetProperty(e.FieldIdentifier.FieldName);

    if (property is null)
        return;

    IEnumerable<ValidationAttribute> attributes = property.GetCustomAttributes<ValidationAttribute>();

    List<string> errors = new List<string>();

    if(Errors.ContainsKey(e.FieldIdentifier.FieldName))
        Errors.Remove(e.FieldIdentifier.FieldName);

    foreach(ValidationAttribute attribute in attributes)
    {
        if (!attribute.IsValid(property.GetValue(Model)))
            errors.Add(attribute.ErrorMessage);
    }

    if (errors.Count > 0)
        Errors[e.FieldIdentifier.FieldName] = errors;
}

Crashing on this place. Only if I change field ConfirmPassword!

        if (!attribute.IsValid(property.GetValue(Model)))

Debugger says e.FieldIdentifier.FieldName is "ConfirmPassword"

Model definition

[Required, Display(Name = "Password", ResourceType = typeof(Translations.Accounts)), DataType(DataType.Password)]
public string Password { get; set; }
[Required, Display(Name = "ConfirmPassword", ResourceType = typeof(Translations.Accounts)), DataType(DataType.Password), CompareProperty("Password", ErrorMessageResourceName = "Compare", ErrorMessageResourceType = typeof(Translations.Accounts))]
public string ConfirmPassword { get; set; }

Razor

<div class="form-group">
    <label for="ConfirmPassword" class="control-label">@Translations.ConfirmPassword</label>
    <InputText type="password" name="ConfirmPassword" class="@($"form-control {ModelContext.DisplayError(x => x.ConfirmPassword)}")" placeholder="@Translations.ConfirmPassword" required="@(!Edit || !string.IsNullOrEmpty(Model.Password))" minlength="@Policy.MinLength" maxlength="@Policy.MaxLength" @bind-Value="Model.ConfirmPassword" />

    @if (ModelContext.HasError(x => x.ConfirmPassword))
    {
    <i class="fas fa-exclamation-triangle invalid-feedback"></i>
    <span class="invalid-feedback"><ValidationMessage For="@(() => Model.ConfirmPassword)" /></span>
    }
</div>

Exceptions (if any)

blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object.
  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) <0x2877a78 + 0x000ce> in <filename unknown>:0 
--- End of stack trace from previous location where exception was thrown ---

  at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion (System.Threading.Tasks.Task task) <0x2ffc038 + 0x000da> in <filename unknown>:0 
  at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask (System.Threading.Tasks.Task taskToHandle) <0x2ffffc0 + 0x000b6> in <filename unknown>:0 

Further technical details

  • ASP.NET Core version 3.1.4
  • VS 16.0

Any idea how to get more debug info?

@glararan
Copy link
Author

glararan commented Jun 9, 2020

Well I find problem.. Its CompareProperty attribute.

@glararan glararan changed the title Webassembly reflection error (internal?) Webassembly CompareProperty reflection crash Jun 9, 2020
@glararan
Copy link
Author

glararan commented Jun 9, 2020

If anyone else struggles with same issue. I did workaround.

However I dont know whats happening inside IsValid?

foreach(ValidationAttribute attribute in attributes)
{
    if (attribute is ComparePropertyAttribute comparePropertyAttribute)
    {
        PropertyInfo compareProperty = Model.GetType().GetProperty(comparePropertyAttribute.OtherProperty);

        if (compareProperty != null && (string)property.GetValue(Model) != (string)compareProperty.GetValue(Model))
            errors.Add(comparePropertyAttribute.ErrorMessage);
    }
    else if (!attribute.IsValid(property.GetValue(Model)))
        errors.Add(attribute.ErrorMessage);
}

@mkArtakMSFT
Copy link
Member

Thanks for contacting us.
It's not clear where in Blazor the error is here. The exception you're referring to indicates an error from your own code. If you believe there is an issue in the framework, please file a new issue with a minimalistic code to help repro the error.

@glararan
Copy link
Author

glararan commented Jun 9, 2020

@mkArtakMSFT well issue is in IsValid method of class ComparePropertyAttribute inside nuget package Microsoft.AspNetCore.Components.DataAnnotations.Validation which should be in this repo right?

@mkArtakMSFT
Copy link
Member

@glararan can you please provide a repro project?

@mkArtakMSFT mkArtakMSFT reopened this Jun 11, 2020
@glararan
Copy link
Author

@mkArtakMSFT
successfully reproduced at https://github.com/glararan/22709/tree/master/22709

steps:

launch project
navigate into 22709
type something to "Password"
type something to "Confirm Password"
unfocus Confirm Password
exception is thrown

@pranavkm pranavkm transferred this issue from dotnet/aspnetcore Sep 19, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Reflection untriaged New issue has not been triaged by the area owner labels Sep 19, 2020
@pranavkm pranavkm changed the title Webassembly CompareProperty reflection crash CompareAttribute.IsValid results in null ref Sep 19, 2020
@ghost
Copy link

ghost commented Sep 19, 2020

Tagging subscribers to this area: @ajcvickers
See info in area-owners.md if you want to be subscribed.

@pranavkm
Copy link
Contributor

Moved to the runtime repo to provide a better error message for this case. That said, you are going to unable to call IsValid on individual attributes and get the right result. Have a look at how Blazor implements it's validation: https://github.com/dotnet/aspnetcore/blob/f52077f599f0d3b4545d8f87a0c3d15217b33069/src/Components/Forms/src/EditContextDataAnnotationsExtensions.cs#L26

@ajcvickers ajcvickers added this to the Future milestone Sep 30, 2020
@ajcvickers ajcvickers removed the untriaged New issue has not been triaged by the area owner label Sep 30, 2020
@kaide
Copy link

kaide commented Nov 4, 2022

I got the same null issue with CompareAttribute.IsValid(object value), so I use GetValidationResult(object value, ValidationContext validationContext) instead.

vvg88 added a commit to vvg88/runtime that referenced this issue Dec 12, 2024
The fix is done to avoid NRE when CompareAttribute's implementation of IsValid(object? value, ValidationContext validationContext) is called with validationContext == null.

Fix dotnet#42490
@dotnet-policy-service dotnet-policy-service bot added the in-pr There is an active PR which will close this issue when it is merged label Dec 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.ComponentModel.DataAnnotations in-pr There is an active PR which will close this issue when it is merged
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants