Finally, I have implemented both client-side and server-side validation to achieve my requirement. Here is the complete code:
Enum
public enum BusinessType
{
Personal,
Business
}
Profile Model
public class Profile
{
[Required(ErrorMessage = "Please enter name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter email")]
[EmailAddress]
public string Email { get; set; }
[Required(ErrorMessage = "Please choose business type")]
[EnumDataType(typeof(BusinessType))]
public BusinessType BusinessType { get; set; }
[RequiredIf("BusinessType", BusinessType.Business, ErrorMessage = "VAT number is required")]
[Display(Name = "VAT Number")]
public string VATNumber { get; set; }
}
RequiredIfAttribute class
public class RequiredIfAttribute : ValidationAttribute, IClientModelValidator
{
public string PropertyName { get; set; }
public object Value { get; set; }
public RequiredIfAttribute(string propertyName, object value, string errorMessage = "")
{
PropertyName = propertyName;
ErrorMessage = errorMessage;
Value = value;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var instance = validationContext.ObjectInstance;
var type = instance.GetType();
var proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
if (proprtyvalue != null)
{
if (proprtyvalue.ToString() == Value.ToString() && value == null)
{
return new ValidationResult(ErrorMessage);
}
}
return ValidationResult.Success;
}
public void AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-vatNumber", ErrorMessage);
context.Attributes.Add("data-val-vatNumber-businessType", Value.ToString());
}
}
requiredIfBusinessTypeValidate.js
$.validator.addMethod('vatNumber', function (value, element, params) {
var genre = $(params[0]).val(), businessType = params[1], vat = value;
var selectedBusinessType = $("#BusinessType option:selected").text();
if (selectedBusinessType === businessType) {
if (value.length === 0) {
return false;
} else {
return true;
}
} else {
return true;
}
});
$.validator.unobtrusive.adapters.add('vatNumber', ['businessType'], function (options) {
var element = $(options.form).find('select#BusinessType')[0];
options.rules['vatNumber'] = [element, options.params['businessType']];
options.messages['vatNumber'] = options.message;
});
View
<h4>Profile</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Index">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email" class="control-label"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="BusinessType" class="control-label"></label>
<select asp-for="BusinessType" class="form-control" asp-items="Html.GetEnumSelectList<BusinessType>()">
<option value="">Choose</option>
</select>
<span asp-validation-for="BusinessType" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="VATNumber" class="control-label"></label>
<input asp-for="VATNumber" class="form-control" />
<span asp-validation-for="VATNumber" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script src="~/js/requiredIfBusinessTypeValidate.js"></script>
}
Controller
public class ProfileController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(Profile profile)
{
if (ModelState.IsValid)
{
// Write business logic here ...
}
return View(profile);
}
}