Validating forms programmatically via an Extension

Validating forms programmatically via an Extension

  
In some cases my forms have so many form elements requiring validation (e.g., 20+) that it's impractical to use the visual editor for validation. Each validation seems to require a pair of nodes for the "If" and "Assign". Even if I could get it down to one extra node per validation, that's still going to be a mess for some [larger] forms.

The solution I found was to write a .NET extension that performs the validations in code. This seems to be a good fit for an extension since I have the power of the entire .NET framework at my disposal. The primary benefit, however, is that I can perform many validations inside this code but only have to drop a single "Validate_Form_123" action onto the canvas during my Edit/Save processing.

Unfortunately, my approach has a dependency on the underlying Agile Platform objects which probably isn't entirely kosher from a version upgrade/migration issue. I'm wondering if anyone has solved this in a different way (short of a huge Action diagram and also not relying on client-side Javascript which can be bypassed)?

Below is some sample code I used in my extension Action (full file attached). Again, I'd appreciate feedback/advice on doing this in a supported way since I doubt my GetWidget(...) method is kosher. :o)

Thanks for your time!
- - -

public void MssCRF1_Validate() {
EnforceRegexMatch("wtCRF1_SiteId", "^9.*", "Site ID must start with 9");
EnforceNumeric("wtCRF1_VisitNumber", "Visit number must be numeric");
} // MssCRF1_Validate

This code relies on some helper methods, samples of which follow:

/// <summary>
/// Validate that the widget's "typed value" matches a regex, setting Valid and ValidationMessage as appropriate
/// </summary>
protected void EnforceRegexMatch(string field, string regex, string errorMessage) {
IWidgetRuntimeProperties widget = GetWidget(field);
if (!Regex.IsMatch(widget.TypedValue, regex))
{
widget.Valid = false;
widget.ValidationMessage = errorMessage;
}
}

/// <summary>
/// Validate that the widget's "typed value" is numeric (or blank), setting Valid and ValidationMessage as appropriate
/// </summary>
protected void EnforceNumeric(string field, string errorMessage) {
EnforceRegexMatch(field, "^[0-9]*$", errorMessage);
}

/// <summary>
/// Given the ID of a widget inside Agile Platform, return the widget for use in validations/etc.
/// </summary>
protected IWidgetRuntimeProperties GetWidget(string id) {
OSPage page = (OSPage)HttpContext.Current.Handler;
IWidgetRuntimeProperties widget = (IWidgetRuntimeProperties)page.FindControl(id);
if (widget == null)
{
throw new Exception(String.Format("Extension error - Could not find widget with ID={0}", id));
}
return widget;
}

Hi Eric,

 

Congratulations, that can be a truly useful piece of code for advanced validations!

 

As for your question you might know that MssCRF1_Validate() isn't kosher because you have the widget ids there, but you could make EnforceRegexMatch public and use that in your eSpace and send the widget id runtime properties as arguments.

 

As for the way to do the GetWidget() it will work now and in the next version and we can help you change it if there are breaking changes in future versions.

 

I would also like to remind you that data type validation (e.g. numeric, date) is already performed implicitly by the platform. On the server side you just need to check for the valid runtime property of the EditRecord widget.

 

Let me know if this was clear.

 

Cheers,
Tiago Simões

Tiago,
Yes, your answer was very clear. Thank you!

> Congratulations, that can be a truly useful piece of code for advanced validations!

Thanks. It took a little bit of exploration but it seems like it will be helpful for larger forms.

> As for the way to do the GetWidget() it will work now and in the next version and we
> can help you change it if there are breaking changes in future versions.

Wow, that is fantastic! I'm not used to a vendor being so willing to help make sure my system continues to work, thank you!

> ...is already performed implicitly by the platform

Yes, I knew that and the product does have a number of great validations. :-) I just picked this example because I could use it to demonstrate, in only a short bit of code, the idea of what I was after.

Thanks for the speedy reply and your willingness to help us use your product!
Cheers,
Eric Kramer
Nationwide Children's Hospital
Columbus, OH
http://nationwidechildrens.org
Hi Eric,

I'd like to share my point of view with you if you don't mind. First of all the extension is a great piece of work, congratulations!

Now, I've since this picture happen a couple of times and I think that you're following the hardest path. I also understand that .NET might be your comfort zone but I think it's not a very good best practice to hide business logic, in this case in terms of data validation, behind an Extension.

From your examples I see that all the validations you're trying to perform can be done inside Service Studio, and some of them automatically.
  • The OutSystems Platform validates data types both client and server side, so I see no need to have a EnforceNumeric validation. It also validations mandatory fields. Tiago already exposed this. Do you have questions using built-in validations?
  • You can also implement you're own generic validations to be client or server side. Check ValidationTools Extension (http://www.outsystems.com/NetworkSolutions/ProjectDetail.aspx?ProjectId=42).
  • The Text Extension exposes the RegEx methods to Service Studio, so pattern validations can also be done inside Service Studio.
So what do you gain with having this inside Service Studio, you have to put a pair of if and assign for special validations but the benefit of having all the business logic exposed in the action flow and the flexibility you get to change the form and validations are greater I think, you gain in code readability and maintainability.

Hope this helps you.
André