Reputation: 1746
I have the following class which is being used as an input model for an EditForm in a Blazor server side application.
public class KundeInput
{
[ValidateComplexType]
public List<AnsprechpartnerInput> Ansprechpartner { get; } = new List<AnsprechpartnerInput>();
public string? Kundennummer { get; }
[Required]
[MaxLength(60)]
public string Firma { get; set; } = String.Empty;
[MaxLength(60)]
public string? Name2 { get; set; }
[MaxLength(60)]
public string? Name3 { get; set; }
}
As you can see, my model contains a list of another model called AnsprechpartnerInput. Here is this model:
public class AnsprechpartnerInput
{
public string? Kundennummer { get; set; }
public int Nummer { get; } = -1;
[MaxLength(60)]
[Required]
public string Vorname { get; set; } = String.Empty;
[MaxLength(60)]
[Required]
public string Nachname { get; set; } = String.Empty;
[MaxLength(40)]
[Required]
public string? Bereich { get; set; }
/ * More properties */
}
The validation works fine. However, once I have multiple invalid AnsprechpartnerInput models in my list, the ValidationSummary becomes a mess. Because it displays e.g. 5 times field xyz is invalid.
I know I can set a custom message with the ErrorMessage property but I am not able to use other attributes from my model in this message.
What I want to achive is this:
[Required(ErrorMessage = $"Vorname of {Kundennummer} is required")]
public string Vorname { get; set; } = String.Empty;
I already tried to change the message with reflection but accoridng to Microsoft this way is not recommend or supported https://github.com/dotnet/aspnetcore/issues/25611
Is there any way to get it to work? I thought of string replacement but I am not sure how I can figure out the right model for my ValidationMessage.
Also is there any way to validate the items of the list by one and get a boolean result? Let's say I want to achive this:
@foreach (var ansprechpartner in Input.Ansprechpartner)
{
if (Input.SelectedAnsprechpartner is null)
Input.SelectedAnsprechpartner = ansprechpartner;
<a @onclick="() => Input.SelectedAnsprechpartner = ansprechpartner"
class="@GetNavListClass(Input.SelectedAnsprechpartner == ansprechpartner)"
id="list-ansprechpartner-tab-@(ansprechpartner.Nummer)"
data-toggle="list"
href="#list-ansprechpartner-@(ansprechpartner.Nummer)"
role="tab"
aria-controls="@(ansprechpartner.Nummer)">
@((MarkupString)(ansprechpartner.Nummer < 0 ? "<span class=\"font-weight-bold\">NEU</span>" : $"({ansprechpartner.Nummer})")) @ansprechpartner.Vorname @ansprechpartner.Nachname
</a>
// When the model ansprechpartner is invalid, I want to display an icon
}
Thanks for any help! PS: Blazor rocks!
Upvotes: 5
Views: 5964
Reputation: 1
public class RequiredCollectionAttribute : ValidationAttribute
{
private readonly string _dependentProperty;
public RequiredCollectionAttribute(string dependentProperty)
{
_dependentProperty = dependentProperty;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var property = validationContext.ObjectType.GetProperty(_dependentProperty);
if (property == null)
{
return new ValidationResult($"Unknown property: {_dependentProperty}");
}
var dependentValue = property.GetValue(validationContext.ObjectInstance, null);
if (dependentValue == null)
{
return ValidationResult.Success;
}
IEnumerable<string> isCollection;
try
{
isCollection = (IEnumerable<string>)dependentValue;
}
catch (InvalidCastException)
{
return new ValidationResult($"Property {_dependentProperty} is not of type IEnumerable<string>.");
}
if (isCollection == null || (isCollection != null && isCollection.Count() == 0))
{
return new ValidationResult(ErrorMessage ?? "This field is required.");
}
return ValidationResult.Success;
}
}
[RequiredCollection("SelectedProjectManagers", ErrorMessage = "Project Manager(s) is required.")]
public IEnumerable<string>? SelectedProjectManagers { get; set; }
Upvotes: 0
Reputation: 251
You should use a custom validation attribute where you can explicitly add any error message you want
public class KundennummerValidationAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var model = (AnsprechpartnerInput)validationContext.ObjectInstance;
if(string.IsNullOrEmpty((string)value))
{
return new ValidationResult($"Vorname of {model.Kundennummer} is required", new[] { "Kundennummer" });
}
return ValidationResult.Success;
}
}
then use
[KundennummerValidation]
public string Vorname { get; set; } = String.Empty;
result : Validation summary:
Upvotes: 4