Skip to content

CompareAttribute.IsValid results in null ref #42490

Closed
@glararan

Description

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?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions