简体   繁体   中英

Validate on Object then display error using CustomValidator

I'm hoping someone can help me. I want to write custom validation code on directly on the object rather than have to write separate methods for both the website UI and a web service which is using the same objects. Here is the code I have at present, which works but I don't think is the best solution, especially as it means having to use an object where I really just want to use standard string / int etc. I had thought that maybe I could use an attribute on the property of the object but as I can't set the value of the attribute that idea went out the window. Any help would be gratefully received.

Kind regards, Alex

<%@ Register src="TextBoxControl.ascx" tagname="TextBoxControl" tagprefix="uc1" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">

<asp:ValidationSummary ID = "VS" runat="server" />
Name: <uc1:TextBoxControl ID="NameTextBox" runat="server" ErrorMessage="Name is required" />
<br />Postcode:  <uc1:TextBoxControl ID="PostcodeTextBox" runat="server" ErrorMessage="Postcode is required" />
 <asp:Button ID="SubmitButton" runat="server" Text="Submit" OnClick="SubmitButton_OnClick" />
</asp:Content>


public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void SubmitButton_OnClick(object sender, EventArgs e)
    {
        MyObject obj = new MyObject();
        obj.Name = new ValidatedString(NameTextBox.Text);
        obj.Postcode = new ValidatedString(PostcodeTextBox.Text);

        NameTextBox.IsValid = obj.Name.Valid;
        NameTextBox.CustomError = obj.Name.GetErrors();
        PostcodeTextBox.IsValid = obj.Postcode.Valid;
        PostcodeTextBox.CustomError = obj.Postcode.GetErrors();
    }
}

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TextBoxControl.ascx.cs"     Inherits="WebApplication1.TextBoxControl" %>
 <asp:TextBox ID="ValueTextBox" runat="server"></asp:TextBox>
   <asp:CustomValidator ID="CV" runat="server" ControlToValidate="ValueTextBox">*    </asp:CustomValidator>
   <asp:RequiredFieldValidator ID="RFV" runat="server" ControlToValidate="ValueTextBox">*</asp:RequiredFieldValidator>

 public partial class TextBoxControl : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    public string Text
    {
        get
        {
            return ValueTextBox.Text;
        }
    }

    public string ErrorMessage
    {
        set
        {
            RFV.ErrorMessage = value;
        }
    }

    public bool IsValid
    {
        set
        {
            CV.IsValid = value;
        }
    }

    public string CustomError
    {
        set
        {
            CV.ErrorMessage = value;
        }
    }
}


 public class MyObject
{
    private ValidatedString _name = new ValidatedString();
    public ValidatedString Name
    {
        get{
            return _name;
        }
        set
        {
            if (value.Value.Length > 5)
            {
                value.Errors.Add("Name exceeded maximum length of 5");
                value.Valid = false;
            }
            if (value.Value.Contains("a"))
            {
                value.Errors.Add("Name cannot contain the letter a");
                value.Valid = false;
            }


                _name = value;
        }
    }

    private ValidatedString _postcode = new ValidatedString();
    public ValidatedString Postcode
    {
        get
        {
            return _postcode;
        }
        set
        {
            if (value.Value.Length > 3)
            {
                value.Errors.Add("Postcode exceeded maximum length of 5");
                value.Valid = false;

            }
            if (value.Value.Contains("a"))
            {
                value.Errors.Add("Postcode cannot contain the letter a");
                value.Valid = false;

            }


                _postcode = value;

        }
    }


}

public class ValidatedString
{
    private string _value = string.Empty;
    private bool _valid = true;
    private List<string> _errors = new List<string>();
    public ValidatedString()
    { }

    public ValidatedString(string value)
    {
        _value = value;
    }

    public string Value
    {
        get
        {
            return _value;
        }
        set
        {
            _value = value;
        }
    }

    public bool Valid
    {
        get
        {
            return _valid;
        }
        set
        {
            _valid = value;
        }
    }

    public List<string> Errors
    {
        get
        {
            return _errors;
        }
        set
        {
            _errors = value;
        }
    }


    public string GetErrors()
    {
        string returnValue = string.Empty;
        foreach (string error in Errors)
        {
            returnValue += error + System.Environment.NewLine;
        }
        return returnValue;
    }
}

First of all: seperate your validators and your data. They are two different things. They should not be combined into one class. The validator has logic to validate data. Validating is his responsibility, not holding the data it is validating. Another class, lets say your entity, should hold the data.

Why?

  • In the future your data will have to be transported somewhere else, lets say in a database, in an XML file, over WCF, whatever. I can imagine that you do not want to tranfer all lists with error-messages, etc.
  • Further, validation can be depending on certain conditions like, country. If a country is different from your default country, another postcode-validator is required, but your entity stays the same.
  • You can see this behavior back in .NET. The data-control is seperated from the validation-control. Follow this logic.

Second: You can make a custom validation control. You can choose to run the validation-logic on the client (javascript) or server side. If you choose to run it server-side, you can have one simple function somewhere in a library which will be used by your code and also by the custom validator.

Your validation code for your postcode could be:

// Validates a postcode and returning a list of errors. If the list is empty, the postcode is valid.
public List<string> ValidatePostcode(string postcode)
{
    List<string> errors = new List<string>();
    // Assuming postcode is not null. Otherwise, create another check.
    if (postcode.Length > 3)
        errors.Add("Postcode exceeded maximum length of 5");
    if (postcode.Contains("a"))
        errors.Add("Postcode cannot contain the letter a");
    return errors;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM