0

I am currently trying to make a site on asp.net core. When i press the submit button, i want all the validation messages to come up if there is incorrect input.

enter image description here

For now, i have the name and the phone number validation messages working using 'asp-validation-for=Client.Name' and Client.ContactNumber. Now i want to be able to validate from the server side if the user has checked at least one of the boxes off, or filled in the 'Other' field. So i tried to see if i can make a custom attribute which would validate it but havent gotten any luck. I have tried sending in the properties of the Client class but it throws an error saying "An object reference is required for the non-static field, method, or property 'Client.'". I have also tried the top solution here CS0120: An object reference is required for the nonstatic field, method, or property 'foo' , but I think in my case those solutions are not possible.

My code for the files that i am working with are below

Code for Client.cs (model class)

public class Client
{
    //some attributes

    [Required]
    public string Name { get; set; }

    [Required]
    [DisplayName("Bookkeeping")]
    public bool Bookkeeping { get; set; }

    [Required]
    [DisplayName("Personal Income Taxation")]
    public bool Personal_Income_Taxation { get; set; }

    [Required]
    [DisplayName("Self-Employed Business Taxes")]
    public bool Self_Employed_Business_Taxes { get; set; }

    [Required]
    [DisplayName("GST/PST/WCB Returns")]
    public bool GST_PST_WCB_Returns { get; set; }

    [Required]
    [DisplayName("Tax Returns")]
    public bool Tax_Returns { get; set; }

    [Required]
    [DisplayName("Payroll Services")]
    public bool Payroll_Services { get; set; }

    [Required]
    [DisplayName("Previous Year Filings")]
    public bool Previous_Year_Filings { get; set; }

    [Required]
    [DisplayName("Govt. Requisite Form Applicaitons")]
    public bool Government_Requisite_Form_Applications { get; set; }

    public string Other { get; set; }

    [CheckboxAndOtherValidation(bookkeeping: Bookkeeping,
        personal_Income_Taxation: Personal_Income_Taxation,
        self_Employed_Business_Taxes: Self_Employed_Business_Taxes,
        gST_PST_WCB_Returns: GST_PST_WCB_Returns,
        tax_Returns: Tax_Returns,
        payroll_Services: Payroll_Services,
        previous_Year_Filings: Previous_Year_Filings,
        government_Requisite_Form_Applications: Government_Requisite_Form_Applications,
        other: Other)]
    public bool AreCheckboxesAndOtherValid { get; set; }

FreeConsultation.cshtml (view page)

<div class="container" style="padding:30px;">
    <br />
    <h1 class="text-info">Create New Client</h1><br />
    <form method="post">
        <div class="text-danger" asp-validation-summary="ModelOnly"></div>
        <div class="form-group row">
            <div class="col-3">
                <label asp-for="Client.Name"></label>
            </div>
            <div class="col-6">
                <input type="text" asp-for="Client.Name" class="form-control" />
            </div>
            <span class="text-danger col-3" asp-validation-for="Client.Name"></span>
        </div>
    <!-- More code -->

My utility class i created for custom validation attribute - CheckboxAndOtherValidation.cs

    public class CheckboxAndOtherValidation : ValidationAttribute
{
    private readonly bool Bookkeeping;
    private readonly bool Personal_Income_Taxation;
    private readonly bool Self_Employed_Business_Taxes;
    private readonly bool GST_PST_WCB_Returns;
    private readonly bool Tax_Returns;
    private readonly bool Payroll_Services;
    private readonly bool Previous_Year_Filings;
    private readonly bool Government_Requisite_Form_Applications;
    private readonly string Other;

    public CheckboxAndOtherValidation(bool bookkeeping,
        bool personal_Income_Taxation,
        bool self_Employed_Business_Taxes,
        bool gST_PST_WCB_Returns,
        bool tax_Returns,
        bool payroll_Services,
        bool previous_Year_Filings,
        bool government_Requisite_Form_Applications,
        string other)
    {
        this.Bookkeeping = bookkeeping;
        this.Personal_Income_Taxation = personal_Income_Taxation;
        this.Self_Employed_Business_Taxes = self_Employed_Business_Taxes;
        this.GST_PST_WCB_Returns= gST_PST_WCB_Returns;
        this.Tax_Returns = tax_Returns;
        this.Payroll_Services = payroll_Services;
        this.Previous_Year_Filings = previous_Year_Filings;
        this.Government_Requisite_Form_Applications = government_Requisite_Form_Applications;
        this.Other = other;

    }

    public override bool IsValid(object value)
    {
        return base.IsValid(value);
    }
}

Is there any other way to tackle this? (Preferably with custom attribute). First time posting a question so pardon me if there is anything missing. Thanks

EDIT

I was able to make the checkbox error come from the server side with the help of a solution, but i still have the issue that when i press the submit button, the checkbox error doesn't come at the same time as the other two. By following a tutorial, i was able to show the other two errors from the client side by including this piece of code in my view which comes with the creation of an asp.net core project

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

_ValidationScriptsPartial.cshtml

<environment include="Development">
    <script src="~/Identity/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</environment>
<environment exclude="Development">
    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.17.0/jquery.validate.min.js"
            asp-fallback-src="~/Identity/lib/jquery-validation/dist/jquery.validate.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator"
            crossorigin="anonymous"
            integrity="SOME INFO">
    </script>
    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.9/jquery.validate.unobtrusive.min.js"
            asp-fallback-src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
            crossorigin="anonymous"
            integrity="SOME INFO">
    </script>
</environment>
gupta_28
  • 17
  • 2
  • 7

1 Answers1

2

Some references are here

  1. Article custom-data-annotation-validation-in-mvc
  2. Source code of CompareAttribute.cs and ComparePropertyAttribute.cs
  3. 3rd-party ExpressiveAnnotations

So in a similar way, a custom ValidationAttribute can use reflection to get runtime value by its property name (the name from declaration or argument) to see if the property have the required value or format you need.

public class CheckboxAndOtherValidation : ValidationAttribute
{
    readonly object TRUE = true;
    string[] _alltheOtherProperty;

    public CheckboxAndOtherValidation(params string[] alltheOthersProperty)
    {
        _alltheOtherProperty = alltheOthersProperty;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (_alltheOtherProperty?.Count() > 0 != true)
        {
            return ValidationResult.Success;
        }

        var otherPropertyInfo = validationContext.ObjectType.GetProperty(nameof(Client.Other));
        if (otherPropertyInfo != null)
        {
            object otherPropertyValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);
            if (otherPropertyValue != null && !string.IsNullOrEmpty(otherPropertyValue.ToString()))
            {
                return ValidationResult.Success;
            }
        }

        for (var i = 0; i < _alltheOtherProperty.Length; ++i)
        {
            var prop = _alltheOtherProperty[i];
            var propertyInfo = validationContext.ObjectType.GetProperty(prop);
            if (propertyInfo == null)
            {
                continue;
            }

            object propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);
            if (Equals(TRUE, propertyValue))
            {
                return ValidationResult.Success;
            }
        }

        return new ValidationResult("Must exist at least one field is true", _alltheOtherProperty);
    }
}

Cus I choose passing property name array list as argument, now class Client could have a simplified and clearer usage like this,

public class Client
{
    [CheckboxAndOtherValidation(nameof(Bookkeeping),
        nameof(Personal_Income_Taxation),
        nameof(Self_Employed_Business_Taxes),
        nameof(GST_PST_WCB_Returns),
        nameof(Tax_Returns),
        nameof(Payroll_Services),
        nameof(Previous_Year_Filings),
        nameof(Government_Requisite_Form_Applications))]
    public bool AreCheckboxesAndOtherValid { get; set; }
}    
nwpie
  • 665
  • 11
  • 24
  • correct me if im wrong, but in the first if statement, you're checking if _alltheOtherProperty has more than 0 values, the second if statement you're checking if the "Other" field is not null, and the for loop in the end checks if all of them are not false? – gupta_28 May 12 '20 at 00:30
  • @gupta_28 I think you've read my example very well. Feel free to modify to meet your needs. For instance, you can return errors if `_alltheOtherProperty` is NullOrEmpty array. – nwpie May 12 '20 at 01:48
  • also, what is "ClientAddressInfo"? – gupta_28 May 12 '20 at 23:45
  • @gupta_28 Sorry it's typo. I've replaced with your class **Client**. Please check again. – nwpie May 13 '20 at 01:28
  • okay i thought so. So i tried using your solution, and what im getting is that when i hit the submit button, i still don't get the checkbox error that i am looking for. I tried adding the "ErrorMessage = 'blah'" to my client class as part of the attribute but it is still not working. I put a debugger in the IsValid method but it only gets hit if i input a valid name and contact number. Is there a way to get the message along with the other two error messages that i display? – gupta_28 May 13 '20 at 04:18
  • @gupta_28 You can double check and follow this article [custom-data-annotation-validation-in-mvc](https://www.c-sharpcorner.com/article/custom-data-annotation-validation-in-mvc/) to test smaller pieces of your model. Since I've tested 3 scenarios which are all hit the correct results, `1) $.Others is not empty -> valid, 2) $.Others is null, one of the flags is true -> valid, 3) $.Others is null, all of the flags are false -> invalid`. So the logic parts should work fine, the problem you occurred might be property name dismatch or data type issues. – nwpie May 13 '20 at 05:04
  • ok thanks that helped. Do you have any idea about how to show the errors from the client side? (i updated the question) – gupta_28 May 13 '20 at 06:37
  • You are welcome. Have you tried `@Html.ValidationMessageFor(model => model.AreCheckboxesAndOtherValid, "", new { @class = "text-danger" })` ? See [custom-data-annotation-validation-in-mvc](https://www.c-sharpcorner.com/article/custom-data-annotation-validation-in-mvc/) for more detail please. – nwpie May 13 '20 at 06:43
  • @gupta_28 Don't have any clue yet. Try simplify your question and create a new post . You might get new answers. – nwpie Jun 01 '20 at 06:18