ASP.NET Validation Group Workarounds



  • @abarker said:

    Status: Wanting to strangle the idiot who decided that ASP.NET validation controls can only belong to one validation group and that you would only ever want to validate one validation group at a time.

    Moving conversation here because it's getting bigger than I expected.



  • @abarker said:

    Status: Wanting to strangle the idiot who decided that ASP.NET validation controls can only belong to one validation group and that you would only ever want to validate one validation group at a time.

    You can handle dynamic groups. It's been way too long since I've done it to remember how, but I've definitely done it. 😀



  • @chubertdev said:

    You can handle dynamic groups. It's been way too long since I've done it to remember how, but I've definitely done it.

    I remember having gone through changing what groups validation controls were in to try and fake it, but it was also done as a hack to get something finished that was behind schedule. I remember that there was an actual fix of some sort for it, but not what it was.



  • I'm settling for overriding IsValidationGroupMatch (code below for those interested) so that I can assign validation controls to multiple groups. There are two downsides to my solution:

    1. It only works client side. I've determined that in my situation it's ok, because disabling the javascript on the pages I'm working on would cause other issues anyway.
    2. The normal pattern of setting up a button to trigger validation (CausesValidation="true" ValidationGroup="Group") doesn't always work. From my testing, it appears that ASP.NET tries to be smart about the validation and if it determines that there are no ValidationControls in a group, then it doesn't auto generate the client script for triggering the client validation. As a result, I have to do CausesValidation="false" OnClientClick="return Page_ClientValidate('Group');". But it works!
    /*
     * Modify the behavior of the client side validation group matching to allow a validation control to be part of multiple validation groups.
     * To take advantage of this, a triggering control needs to have CausesValidation="false" and  OnClientClick="return Page_ClientValidate('{ValidationGroup}');"
     */
    function replaceValidationGroupMatch() {
    	// Make sure that ASP.NET's IsValidationGroupMatch exists.
    	if (typeof (IsValidationGroupMatch) == 'undefined') {
    		throw "ERROR: IsValidationGroupMatch not found!"
    	}
    
    	// Replace ASP.NET's IsValidationGroupMatch with this custom method. The new method allows assigning multiple space delimited
    	// validation groups to a single validator control .
    	IsValidationGroupMatch =
    		function(control, validationGroup) {
    			// Check for global validation conditions (executing validation group <unspecified> or '*')
    			if (!validationGroup || validationGroup == '*') return true;
    
    			// Get the validation group assigned to the control
    			var controlValGroups = [''];
    			if (typeof (control.validationGroup) == 'string') {
    				// Deal with the chance that the control is part of multiple validation groups
    				controlValGroups = control.validationGroup.split(' ');
    			}
    
    			for (var i = 0; i < controlValGroups.length; i++) {
    				if (controlValGroups[i] == validationGroup) return true;
    			}
    
    			// Control group not found in groups to be validate.
    			return false;
    		};
    }
    
    replaceValidationGroupMatch();
    

    One final note: this needs to be in a script file. Trying to embed it in an .aspx page causes the script to try to run before the original IsValidationGroupMatch gets loaded. Putting it in a js file makes it run later, allowing the override to be successful.



  • Another benefit of this override is the ability to assign multiple validation groups to a single ValidationSummary.



  • Yeah, the built-in methods for updating validation controls on the client-side are pretty janky, but you can get them to work.

    I do assume that you're using Page.Validate("ValidationGroup"); on the server-side.



  • @chubertdev said:

    Yeah, the built-in methods for updating validation controls on the client-side are pretty janky, but you can get them to work.

    I do assume that you're using Page.Validate("ValidationGroup"); on the server-side.

    Usually, yes. However, in this case, with this workaround, that's somewhat difficult to achieve. I'm currently working on a page where there are multiple overlapping validation scenarios. For simplicity, let's say there are three controls with three validation scenarios: A, B, and C.

    • In scenario A, controls 1 and 2 need to be validated.
    • in scenario B, controls 2 and 3 need to be validated.
    • in scenario C, all three controls need to be validated.

    To keep things simple, let's say that we just want RequiredFieldValidators. Without overriding anything ASP.NET provides, I need 2 validators on control 1, 3 validators on control 2, and 2 more on control 3. On top of that, I need three ValidationSummary controls. Scale that up to a few dozen controls that need validation, and things quickly get out of control.

    The benefit of my current approach is that each control gets exactly one validator. Then the validator for control 1 has ValidationGroup="A C", for control 2 you use ValidationGroup="A B C", and for control 3 you use ValidationGroup="B C". Then when call Page_ClientValidate('A'); on client side, controls 1 and 2 get validated.

    This makes server side validation impractical, because now you would need something like:

    Page.Validate("A C");
    if (!Page.IsValid) return;
    
    Page.Validate("A B C");
    if (!Page.IsValid) return;
    

    For more complicated situations, this could easily get out of control. Like I said before, it's acceptable in my current situation.



  • @abarker said:

    This makes server side validation impractical, because now you would need something like:

    code example

    For more complicated situations, this could easily get out of control. Like I said before, it's acceptable in my current situation.

    It's messy, but you can tuck it away in some private method to help handle. Course if you have weird validation sets like that it also means that your page is more complicated than it should be anyway (note: a great many of mine are like that due to customer doing page/screen layouts).



  • @locallunatic said:

    It's messy, but you can tuck it away in some private method to help handle. Course if you have weird validation sets like that it also means that your page is more complicated than it should be anyway (note: a great many of mine are like that due to customer doing page/screen layouts).

    Yes, the page I'm currently working on is specifically to fulfill a client request. If I had any say in the matter, I would have rejected the request as unfeasible.



  • @abarker said:

    Yes, the page I'm currently working on is specifically to fulfill a client request.

    The extra complexity of the server side validation is part of fulfilling that. Can't just go with client side validation or it will bite you in the ass.



  • In that case, I'd have two separate validaiton controls for control 2.

    Scenario A:

    Page.Validate("OneAndTwoA");
    

    Scenario B:

    Page.Validate("TwoBAndC");
    

    Scenario C:

    Page.Validate("OneAndTwoA");
    Page.Validate("TwoBAndC");
    

    And enabled/disable the groups, not the controls, on the client-side.



  • @chubertdev said:

    In that case, I'd have two separate validaiton controls for control 2.

    ...

    And enabled/disable the groups, not the controls, on the client-side.

    That's great for my simplified example. My actual case has a few dozen controls in four validation scenarios. The solution I mentioned actually helps simplify things. After comments above, and wrestling with my conscience (my conscience won), I'm working on a similar server-side solution.

    Also, you need the following in Scenario C:

    Page.Validate("OneAndTwoA");
    if (!Page.IsValid) return;
    Page.Validate("TwoBAndC");
    if (!Page.IsValid) return;
    

    The way you wrote it, the first validation check could fail, and the second could pass, and you'd never know it.


  • FoxDev

    This post is deleted!


  • How's that provide context?


  • FoxDev

    wrong thread...

    my bad.



  • @abarker said:

    That's great for my simplified example. My actual case has a few dozen controls in four validation scenarios. The solution I mentioned actually helps simplify things. After comments above, and wrestling with my conscience (my conscience won), I'm working on a similar server-side solution.

    Also, you need the following in Scenario C:

    Page.Validate("OneAndTwoA");
    if (!Page.IsValid) return;
    Page.Validate("TwoBAndC");
    if (!Page.IsValid) return;
    

    The way you wrote it, the first validation check could fail, and the second could pass, and you'd never know it.

    Page.Validate("OneAndTwoA");
    //if (!Page.IsValid) return;
    Page.Validate("TwoBAndC");
    if (!Page.IsValid) return;
    


  • This topic was automatically closed after 60 minutes. New replies are no longer allowed.





  • @chubertdev said:

    ```
    Page.Validate("OneAndTwoA");
    //if (!Page.IsValid) return;
    Page.Validate("TwoBAndC");
    if (!Page.IsValid) return;

    
    Trust me, you need that first IsValid check. Let me illustrate:
    
    

    Page.Validate("OneAndTwoA"); // Something fails here.
    Page.Validate("TwoBAndC"); // Everything succeeds here.
    if (!Page.IsValid) return; // Page.IsValid will be true here. The failure is lost.

    
    That extra check that I inserted before catches the failure in OneAndTwoA, preventing it from getting lost. True, you can't see all the error messages in a scenario where there are errors in both groups, but unless you are willing to override the default .NET behavior, you just have to deal with that.


  • Maybe I had something like this:

    Page.Validate("OneAndTwoA") && Page.Validate("TwoBAndC");
    if(!Page.IsValid) { return; }
    

    I can't remember, my current job prevents me from actually coding. I was going to fire up VS .NET today, but was way too busy.



  • Nix that, it's a void.

    Maybe this.

    Page.Validate("OneAndTwoA");
    if(Page.IsValid)
    {
       Page.Validate("TwoBAndThree"); //just noticed this should be Three, not C
       if(!Page.IsValid) { return; }
    }
    else
    { return; }
    

  • Discourse touched me in a no-no place

    @system said:

    This topic was automatically closed after 60 minutes. New replies are no longer allowed.

    ??


  • ♿ (Parody)

    I think he was trying out new powers.


  • BINNED

    @boomzilla said:

    I think he was trying out new powers

    HULK NEEDS MOAR POWER



    1. Then it shouldn't have been attributed to @system ...

    B) And the fact that this thread didn't start in One Post shouldn't have (or never used to) apply the closing attribute onto the thread

    iii) And why were regular members able to post between the thread close and thread reopening?

    There's a few things about this thread that are making me itch...

    Edit: just checking that change of ownership results in an edit checkpoint.


  • ♿ (Parody)

    @system said:

    Then it shouldn't have been attributed to @system ...

    Don't all auto-closes go to system? Though...you're right, the replies don't make sense. Unless those were just posts that got moved here from somewhere else, because they keep their timestamps when that happens.

    I guess we'll have to wait for @abarker to wake up.


  • Discourse touched me in a no-no place

    @boomzilla said:

    Don't all auto-closes go to system?

    No, they don't. Only when whoever started the thread doesn't have the close privilege.

    Which, apparently doesn't happen at all frequently, so we're all doing it wrong on here:

    https://meta.discourse.org/t/auto-close-message-can-only-be-inserted-as-staff-users/18576
    https://meta.discourse.org/t/auto-close-message-can-only-be-inserted-as-staff-users/18576/2?u=pjh


  • ♿ (Parody)

    OK, then.


  • Discourse touched me in a no-no place

    That was basically my reaction to the responses on that thread...


  • ♿ (Parody)

    Who you gonna believe, the design document in Jeff's head or your lying eyes?



  • I set the topic to auto-close while I was waiting on feedback of whether to move the conversation here from the status thread. Then I forgot to stop the auto close until after it already happened. And since I'm TL4, not staff, I can't have the auto-close message attributed to me.



  • @chubertdev said:

    Nix that, it's a void.

    Maybe this.

    Page.Validate("OneAndTwoA");
    if(Page.IsValid)
    {
       Page.Validate("TwoBAndThree"); //just noticed this should be Three, not C
       if(!Page.IsValid) { return; }
    }
    else
    { return; }
    ```</blockquote>
    
     That would do it.

  • Discourse touched me in a no-no place

    Ok - that explains the (B) autoclose on 60 mins.

    Still doesn't explain (1) and (iii) though.



  • @system said:

    And why were regular members able to post between the thread close and thread reopening?

    Moved posts from the status thread.

    Basically, I made some mistakes when trying to move a growing conversation to a new topic.



  • @system said:

    1) Then it shouldn't have been attributed to @system

    https://meta.discourse.org/t/auto-close-message-can-only-be-inserted-as-staff-users/18576

    Since auto-closes can only be inserted as staff members, and TL4 is not a staff member, it automatically attributes my auto-closes to @system.


  • Discourse touched me in a no-no place

    @abarker said:

    Moved posts from the status thread.

    Ah - ok, another mystery solved then.

    @abarker said:

    Since auto-closes can only be inserted as staff members, and TL4 is not a staff member, it automatically attributes my auto-closes to @system.

    Ah. That I think is a bug.



  • VS2010 was bringing my laptop to a grinding halt last night, and a ton of Speedway Stout had the same effect on my brain.

    If I have more time, I'll get a better, more complete, example today.



  • @boomzilla said:

    Who you gonna believe, the design document in Jeff's head snowglobe or your lying eyes?

    FTFY


  • BINNED

    I am hereby bestowing on you all a new TDWTF meme:

    A spec someone gives you which is incomplete, and you are expected to understand / extrapolate the rest (for which there is no logical path other than the spec giver's shoulder aliens), shall henceforth be known as "snowglobe spec".


    Filed under: This is not likely to happen, Putting it in the writing, just in case, #profit





  • I don't like what I have, and I still don't. My latest code (after 5 more minutes) doesn't show the error message for all three textboxes if you select rdoAllThree

    You should be able to infer the controls from the code.

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            if (rdoOneAndTwo.Checked)
            {
                if (!ValidateGroup("OneAndTwo")) { return; }
            }
            else if (rdoTwoAndThree.Checked)
            {
                if (!ValidateGroup("TwoAndThree")) { return; }
            }
            else if (rdoAllThree.Checked)
            {
                if (!ValidateGroup("OneAndTwo")) { return; }
                if (!ValidateGroup("TwoAndThree")) { return; }
            }
            else
            {
                throw new InvalidOperationException("What's going on in here?");   
            }
    
            litMessage.Text = "passed validation";
        }
    
        private bool ValidateGroup(string groupName)
        {
            Page.Validate(groupName);
            return Page.IsValid;
        }
    

  • Discourse touched me in a no-no place

    @chubertdev said:

    throw new InvalidOperationException("What's going on in here?");

    +1



  • @chubertdev said:

    I don't like what I have, and I still don't. My latest code (after 5 more minutes) doesn't show the error message for all three textboxes if you select rdoAllThree

    Given the criteria, I don't think it's possible to get all error messages to dispaly from different validation groups, at least not from serever side.



  • It is, you just need one validation control per-group per-validated-control 🙊



  • @boomzilla said:

    the design document

    What, for Discourse? They don't even have a concept of a design document, judging by the product.


  • BINNED

    @Maciejasjmj said:

    What, for Discourse? They don't even have a concept of a design document, judging by the product.

    Yes they do! It involves a lot of whitespace though...


  • ♿ (Parody)

    @Maciejasjmj said:

    They have a document product.

    That's the best unfair edit I could do on short notice and by only removing stuff.


  • Discourse touched me in a no-no place

    @boomzilla said:

    >Maciejasjmj:

    They have a document product.

    That's the best unfair edit I could do on short notice and by only removing stuff.

    "They have a ... product" didn't occur to you?


  • ♿ (Parody)

    @FrostCat said:

    "They have a ... product" didn't occur to you?

    It did, but I like it better with the document still in there.



  • @chubertdev said:

    It is, you just need one validation control per-group per-validated-control 🙊

    Yes, but that kind of ignores my "from different validation groups" condition. Though I did think of one scenario where you can get all error messages to show from server side: execute Page.Validate(). Of course, that runs all validators. If you want to run two of three groups on the page and have all error messages show, .NET basically says "screw you".


Log in to reply