Data Conversion and Validation
 
Published: 16 Jul 2008
Abstract
This article shows techniques to convert data or issues when working with data conversion and validation. Brian examines the techniques involved in Data and Nullable Type Conversion with the help of code snippets in C#. He also provides an outline of String, Data Type ranges, and the different ways with which you can manipulate data input in ASP.NET.
by Brian Mains
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 33358/ 60

Introduction

Data type conversion does not always happen implicitly. To avoid writing a lot of code I have included a helpful technique to parse a range of data values. I also talk about some of the items you have to be aware of in Data Conversion and Validation.

Data Type Conversion

When inputting data from an external source (like a file), it is up to the component to interpret the data type of the content. For instance, in a database system, the data types of each data in .NET have a mapping to their SQL Server or Oracle database equivalent.

When reading data from a component (stream reader or data table), the data that comes into the system may be the value 1. Although it is a number, the underlying data type could be a string, so "1" does not equal 1. Instead, to get the "1" to the correct type, the int.Parse or int.TryParse method has to convert the value correctly. But in developing a generic solution for all of these possible types, this is the purpose of this article.

Sometimes there is a table that has data using many different types (like the profile table), where all these values are stored in an nvarchar or varchar database column. Because the underlying .NET type is string, these values cannot simply be cast to a DateTime or int. This would cause an exception; what is required is to use DateTime.Parse or int.Parse, as long as the value is valid (then TryParse can be used to protect against this).

To perform the type conversion, I have used a helper method to convert the values accordingly.  For instance, suppose you are using a key to retrieve an item from an underlying collection (that may have been populated from a file or database), the following approach can be used to dynamically convert the data to a generic type that meets the following signature.

Listing 1

private T GetValue<T>(string key) { }

After getting a value from a collection, the first check ensures that the data is not null or equal to a database null. If it is one of these values, default(T) is returned. This statement returns the default value for the specified type as a safeguard. For reference types, null is returned.  For value types, the minimum value is returned (integer returns 0). 

The next processing step is if the underlying value is the designated type. If the value matches the generic type exactly, it is returned as is.

Listing 2

if (value is T) return (T)value;

When returning a generic type, sometimes the user wants a string, regardless of whether the underlying implementation is an int, decimal, DateTime, etc.  A little trick to bypass a compiler error is shown below. You cannot simply call ToString() and return that value. Even though the types match in your logic, the compiler does not know that this condition will always be a string because it is solely dealing with a generic type T, and not the underlying representation.

Listing 3

//If the type of T is a string type, then process this
object stringValue = value.ToString();
return (T)stringValue;

For all convertible types, the type of an object can be converted using Convert.Change type.  Most DateTime, string, and most value types support using Convert.ChangeType to change the underlying implementation. However, make sure that the type is convertible first before you call it, because an exception will be thrown if it is not (which may be good or bad depending on the situation).

I found one variance from this approach: nullable types. Nullable types do not support conversion using Convert.ChangeType, and I came up with a workaround below.

Nullable Type Conversion

Nullable types in C# are represented as <type>?, such as int?. Any parameter or field type represented as int? supports a direct null assignment. In addition, the nullable object definition adds two additional properties: HasValue and Value. If you access the Value property when the value is null, an exception is thrown, so where possible check the HasValue property first to ensure the value is not null. Another option is to call the added method, GetValueOrDefault().

Nullable types are represented by the generic class Nullable<int>, and a new nullable object can be constructed with the following long hand syntax.

Listing 4

new Nullable<int>(null);
 new Nullable<int>(1);

Nullable values convert primitive types into reference types, and this has to be handled specially.  The previous situation will not work in the same way. To determine if the type is nullable, use the following line below. I have to thank Microsoft for this one; I stumbled across this as I was examining the code for the JSON serialization process.

Listing 5

if (typeof(T).IsGenericType && 
    typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>))

The ideal situation is to use the Nullable type constructor, but we need to extract the generic type and pass in a new nullable value. For example, Nullable<int> is a reference type, but the generic argument references a value type that can be useful in the code below.

Listing 6

Type parameterType = typeof(T).GetGenericArguments()[0];
Type nullableType = typeof(Nullable<>).MakeGenericType(parameterType);
return (T)Activator.CreateInstance(nullableType, new object[] { 
    Convert.ChangeType(value, parameterType) });

To create a new instance of the nullable type, MakeGenericType takes the Nullable<> type and makes it Nullable<int>.  CreateInstance creates a new instance of the nullable type, safely using Convert.ChangeType to convert the integer value.

To recap, because nullable types are not convertible, you cannot simply say Convert.ChangeType(value, Nullable<int>) and expect this to work. An exception will be thrown.  To handle this, the GetGenericArguments method extracts the "int" type.  A nullable type is generated on the fly and assigned to the nullableType field. Lastly, a new nullable type class is constructed, passing in an integer.

String Ranges

Strings in the .NET Framework support a wide array of character sets and languages. This is good because SQL Server can support different languages and cultures. However, the .NET Framework does not validate the requirement on the length of the string  This means that even though the length of a field in SQL Server is 50 characters long, the .NET Framework string type cannot be limited by that.

It is important to validate the lengths of strings before passing them to the database. This can be troublesome because the error message that returns to the caller is usually not specific enough to identify the specific field over the limit, and it becomes a harder task to identify the data in error.

The UI controls in .NET allow restrictions on the lengths of strings by entering in a maximum limit. A check on the server side can be done as well; though hard-coding a string length can make it difficult to maintain an application (because any changes to the database affect the UI).

Date Type Ranges

Date types in the .NET Framework are supported with SQL Server databases, but you have to be aware of the range of values. For instance, the .NET Framework supports a minimum date value of 1/1/0001, which is not supported in SQL Server.

In SQL Server, the datetime data type minimum value is 1/1/1753 and the smalldatetime data type minimum is 1/1/1900. In the maximum mindset, smalldatetime's value does not fit within the DateTime.MaxValue property range.

If a date outside this range is passed in, a DateTime overflow exception is thrown, which is obviously an issue with data conversion. In addition, the string type does not have any length restrictions, which are not easily catchable unless manually validated.

Data Input

Within ASP.NET, data is most often input through textbox controls, although this varies based upon the need. A Textbox is used to input names, numbers, dates, and inputs of other types.  With the AJAX control toolkit, it is easy to restrict the type of input into the textbox.

When trying to extract the values from the textboxes and converting them to their correct data type, there are some challenges you have to be aware of.  For instance, with a DateTime data type, the input has to be checked to ensure it is correct. If the user enters the following values:  13/13/2008, 1/113/2008, 4/32/2008, when these values are passed to DateTime.Parse or Convert.ToDateTime, an exception will be thrown.

It is better to use DateTime.TryParse instead to get to the date's value. TryParse returns back an empty value, and returns false if the value is invalid. The same concept applies to numerical values; TryParse, at least, fails gracefully. Failing gracefully is a good safeguard to prevent an error.

Ideally, it is best to restrict or prevent the invalid input in the first place. The AJAX control toolkit contains control extenders that restrict the input into it. For instance, the masked edit extender can restrict the input to fit money, date, and numerical input.

Listing 7

<ajax:MaskedEditExtender id="ext" runat="server" Mask="99/99/9999" MaskType="Date" />

As an alternative, the filtered textbox extender restricts the type of characters that can be entered into it.  It can control input to be only numbers, only lowercase letters, uppercase letters, custom letters, or any combination. Below filters out numbers, but allows a decimal point.

Listing 8

<ajax:FilteredTextBoxExtender id="ext" runat="server" 
  FilterType="Numbers,Custom" ValidChars="." />

Make sure you use of the validation controls as well. Validation controls restrict invalid input being entered. For instance, even though the FilteredTextBoxExtender filters out values other than numbers or decimals, it will allow more than one decimal point. The regular expression validator below will prevent that.

Listing 9

<asp:RegularExpressionValidator id="rev" runat="server" ControlToValidate="txt"
ErrorMessage="Enter a valid dollar amount" ValidationExpression="\d+\.\d{2}" />

So plan your interface accordingly.

Conclusion

Data conversion is not as simple as it may seem because the most important thing is the underlying data type.  It is not hard to convert the value, and it can be done using a single method. It is also as important on the UI to ensure your data is correct.



User Comments

Title: good   
Name: jay
Date: 2010-01-29 1:45:56 AM
Comment:
good article.. but confusing words....






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-20 5:56:09 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search