I have written a CustomValidation attribute for a model I am using in an MVC application.
It's not that complex, however for some reason I am getting a really odd NullReferenceException error. I have stripped this right back to the absolute bare minimum just to try and get past this.
The code trips over here if (value != null)
And if I put a breakpoint on the line above it, stepping over generates the exception, almost before the breakpoint.
The weird thing is, I can take value and put it into a string variable and I can see it is valid and present.
I then tried to change the if statement to check that variable is null instead of value and that ALSO yields the error.
What have I done wrong?
The actual Error Response back from the controller is below. The line it references is the If statement.
<h1>An unhandled exception occurred while processing the request.</h1>
<div class="titleerror">NullReferenceException: Object reference not set to an instance of an object.</div>
<p class="location">TechsportiseOnline.Helpers.CustomValidations+BibValidatorAttribute.IsValid(object value, ValidationContext validationContext) in
<code title="C:\Users\matthew.warr\Documents\Git\Website\TechsportiseOnline\Helpers\CustomValidations.cs">CustomValidations.cs</code>, line 22
</p>
CustomAttribute Class
public class BibValidatorAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
value = (string)value;
if (value != null)
{
RaceEntry raceEntry = (RaceEntry)validationContext.ObjectInstance;
var _context = (ApplicationDbContext)validationContext.GetService(typeof(ApplicationDbContext));
var databaseBib = _context.RaceEntries.FirstOrDefault(c => c.Id == raceEntry.Id).BibNumber.ToString();
if (value == databaseBib)
{
return new ValidationResult("The bib number entered already exists");
}
else
{
return ValidationResult.Success;
}
}
else
{
return ValidationResult.Success;
}
}
}
Model
public partial class RaceEntry
{
public long Id { get; set; }
public long RaceID { get; set; }
[NotMapped]
public string RaceName { get; set; }
[NotMapped]
[DisplayFormat(DataFormatString = "{0:dd MMMM yyyy}")]
public DateTime RaceDate { get; set; }
[IgnoreDataMember]
public string OwnerID { get; set; }
[IgnoreDataMember]
public string AthleteUserId { get; set; }
[Display(Name = "Title")]
public string Title { get; set; }
[Display(Name = "First Name *")]
[Required]
public string FirstName { get; set; }
[Display(Name = "Last Name *")]
[Required]
public string LastName { get; set; }
[Display(Name = "Email Address")]
[EmailAddress(ErrorMessage = "Invalid Email Address")]
[RequiredOnlineOnly]
public string Email { get; set; }
[Display(Name = "Date Of Birth *")]
[DataType(DataType.Date)]
[DateOfBirth]
[DisplayFormat(DataFormatString = "{0:dd MMMM yyyy}")]
public DateTime DateOfBirth { get; set; }
[Display(Name = "Gender *")]
public string Gender { get; set; }
[Display(Name = "EA Affiliation Number")]
public string EANumber { get; set; }
[Display(Name = "Club Name")]
public string Club { get; set; }
[Display(Name = "Team")]
public string Team { get; set; }
[Display(Name = "Bib/Race Number")]
[BibValidator (ErrorMessage = "The bib number you have entered already exists")]
public string BibNumber { get; set; }
public DateTime EntryDateTime { get; set; }
[IgnoreDataMember]
public DateTime LastUpdated { get; set; }
public string Status { get; set; }
[Display(Name = "Mobile Phone")]
public string MobilePhone { get; set; }
[IgnoreDataMember]
public string FullMobilePhone { get; set; }
[IgnoreDataMember]
[Display(Name = "Number")]
public string HouseNumber { get; set; }
[Display(Name = "Address *")]
[RequiredOnlineOnly]
public string Address1 { get; set; }
[Display(Name = "Address 2")]
public string Address2 { get; set; }
[Display(Name = "Town/City")]
public string City { get; set; }
[Display(Name = "State")]
public string State { get; set; }
[Display(Name = "County")]
public string County { get; set; }
[Display(Name = "Country")]
public string Country { get; set; }
[Display(Name = "Postcode *")]
[RequiredOnlineOnly]
public string PostCode { get; set; }
public string Source { get; set; }
[Display(Name = "Entry Type")]
public string EntryType { get; set; }
public bool Premium { get; set; }
public bool SMSSent { get; set; }
public bool FinalInstructionsSent { get; set; }
public bool ResultEmailSent { get; set; }
public bool Refunded { get; set; }
public string StripeCode { get; set; }
public decimal AmountPaid { get; set; }
public string AmountPaidCurrency { get; set; }
[IgnoreDataMember]
public string BillingName { get; set; }
[IgnoreDataMember]
public string BillingAddress1 { get; set; }
[IgnoreDataMember]
public string BillingAddress2 { get; set; }
[IgnoreDataMember]
public string BillingCity { get; set; }
[IgnoreDataMember]
public string BillingState { get; set; }
[IgnoreDataMember]
public string BillingCounty { get; set; }
[IgnoreDataMember]
public string BillingCountry { get; set; }
[IgnoreDataMember]
public string BillingPostCode { get; set; }
[IgnoreDataMember]
public string BillingEmail { get; set; }
}
Relevant section of Controller
[HttpPost]
public IActionResult Create([FromBody] RaceEntry item)
{
if (item == null)
{
return BadRequest();
}
//Check bib number
if (!ModelState.IsValid)
{
return BadRequest("Bib number already exists");
}
value = (string)value;, other than cheking it is castable to a string. After this,valueis still of typeobject. I would create a new variable to store the stringNullReferenceExceptionif a class implements an explicit cast operator and that throws aNullReferenceException.