Cómo: Convertir en números datos numéricos proporcionados por el usuario en controles web
Actualización: noviembre 2007
Dado que una página web se puede mostrar en cualquier parte del mundo, los usuarios pueden proporcionar datos numéricos en un control TextBox en un número casi ilimitado de formatos. Por tanto, es muy importante determinar la configuración regional y la referencia cultural del usuario de la página web. Cuando analice los datos proporcionados por el usuario, puede aplicar las convenciones de formato definidas por la configuración regional y la referencia cultural del usuario.
Para convertir la entrada numérica de un control web TextBox en un número
Determine si la matriz de cadenas devuelta por la propiedad HttpRequest.UserLanguages contiene elementos. Si no es así, continúe en el paso 6.
Si la matriz de cadenas devuelta por la propiedad UserLanguages contiene elementos, recupere el primer elemento. El primer elemento indica el idioma y la región predeterminados o preferidos por el usuario.
Cree una instancia de un objeto CultureInfo que represente la referencia cultural preferida del usuario; para ello, llame al constructor CultureInfo.CultureInfo(String, Boolean).
Llame al método TryParse o Parse del tipo numérico en el que desea convertir la entrada del usuario. Utilice una sobrecarga del método TryParse o Parse con un parámetro provider y pásele cualquiera de los elementos siguientes:
El objeto CultureInfo creado en el paso 3.
El objeto NumberFormatInfo devuelto por la propiedad NumberFormat del objeto CultureInfo que se creó en el paso 3.
Si la conversión no se realiza correctamente, repita los pasos 2 al 4 en cada elemento restante de la matriz de cadenas devuelta por la propiedad UserLanguages.
Si la conversión sigue produciendo errores o si la matriz de cadenas devuelta por la propiedad UserLanguages está vacía, analice la cadena usando la referencia cultural de todos los idiomas devuelta por la propiedad CultureInfo.InvariantCulture.
Ejemplo
El ejemplo siguiente corresponde a la página completa de código subyacente de un formulario web en la que se pide al usuario que escriba un valor numérico en un control TextBox y se convierte en un número. Ese número se duplica y se muestra a continuación utilizando las mismas reglas de formato que la entrada original.
Imports System.Globalization
Partial Class NumericUserInput
Inherits System.Web.UI.Page
Protected Sub OKButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles OKButton.Click
Dim locale As String
Dim culture As CultureInfo = Nothing
Dim number As Double
Dim result As Boolean
' Exit if input is absent.
If String.IsNullOrEmpty(Me.NumericString.Text) Then Exit Sub
' Hide form elements.
Me.NumericInput.Visible = False
' Get user culture/region
If Not (Request.UserLanguages.Length = 0 OrElse String.IsNullOrEmpty(Request.UserLanguages(0))) Then
Try
locale = Request.UserLanguages(0)
culture = New CultureInfo(locale, False)
' Parse input using user culture.
result = Double.TryParse(Me.NumericString.Text, NumberStyles.Any, culture.NumberFormat, number)
Catch
End Try
' If parse fails, parse input using any additional languages.
If Not result Then
If Request.UserLanguages.Length > 1 Then
For ctr As Integer = 1 To Request.UserLanguages.Length - 1
Try
locale = Request.UserLanguages(ctr)
' Remove quality specifier, if present.
locale = Left(locale, InStr(locale, ";") - 1)
culture = New CultureInfo(Request.UserLanguages(ctr), False)
result = Double.TryParse(Me.NumericString.Text, NumberStyles.Any, culture.NumberFormat, number)
If result Then Exit For
Catch
End Try
Next
End If
End If
End If
' If parse operation fails, use invariant culture.
If Not result Then
result = Double.TryParse(Me.NumericString.Text, NumberStyles.Any, CultureInfo.InvariantCulture, number)
End If
' Double result
number *= 2
' Display result to user.
If result Then
Response.Write("<P />")
Response.Write(Server.HtmlEncode(Me.NumericString.Text) + " * 2 = " + number.ToString("N", culture) + "<BR />")
Else
' Unhide form.
Me.NumericInput.Visible = True
Response.Write("<P />")
Response.Write("Unable to recognize " + Server.HtmlEncode(Me.NumericString.Text))
End If
End Sub
End Class
using System;
using System.Globalization;
partial class NumericUserInput : System.Web.UI.Page
{
protected void OKButton_Click(object sender, EventArgs e)
{
string locale;
CultureInfo culture = null;
double number = 0;
bool result = false;
// Exit if input is absent.
if (String.IsNullOrEmpty(this.NumericString.Text)) return;
// Hide form elements.
this.NumericInput.Visible = false;
// Get user culture/region
if (!(Request.UserLanguages.Length == 0 || String.IsNullOrEmpty(Request.UserLanguages[0])))
{
try
{
locale = Request.UserLanguages[0];
culture = new CultureInfo(locale, false);
// Parse input using user culture.
result = Double.TryParse(this.NumericString.Text, NumberStyles.Any,
culture.NumberFormat, out number);
}
catch { }
// If parse fails, parse input using any additional languages.
if (!result)
{
if (Request.UserLanguages.Length > 1)
{
for (int ctr = 1; ctr <= Request.UserLanguages.Length - 1; ctr++)
{
try
{
locale = Request.UserLanguages[ctr];
// Remove quality specifier, if present.
locale = locale.Substring(1, locale.IndexOf(';') - 1);
culture = new CultureInfo(Request.UserLanguages[ctr], false);
result = Double.TryParse(this.NumericString.Text, NumberStyles.Any, culture.NumberFormat, out number);
if (result) break;
}
catch { }
}
}
}
}
// If parse operation fails, use invariant culture.
if (!result)
result = Double.TryParse(this.NumericString.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out number);
// Double result.
number *= 2;
// Display result to user.
if (result)
{
Response.Write("<P />");
Response.Write(Server.HtmlEncode(this.NumericString.Text) + " * 2 = " + number.ToString("N", culture) + "<BR />");
}
else
{
// Unhide form.
this.NumericInput.Visible = true;
Response.Write("<P />");
Response.Write("Unable to recognize " + Server.HtmlEncode(this.NumericString.Text));
}
}
}
La propiedad HttpRequest.UserLanguages se rellena a partir de los nombres de la referencia cultural incluidos en los encabezados Accept-Language de una solicitud HTTP. Sin embargo, no todos los exploradores incluyen encabezados Accept-Language en sus solicitudes y además los usuarios pueden suprimir los encabezados por completo. Por ello, es importante tener una referencia cultural de reserva al analizar los datos proporcionados por el usuario. Por lo general, la referencia cultural de reserva es la referencia cultural de todos los idiomas devuelta por la propiedad CultureInfo.InvariantCulture. Los usuarios también pueden proporcionar a Internet Explorer nombres de la referencia cultural escribiéndolos en un cuadro de texto, de modo que es posible que los nombres de la referencia cultural no sean válidos. Por todo esto, es importante utilizar el control de excepciones al crear instancias de un objeto CultureInfo.
Cuando se recupera de una solicitud HTTP enviada por Internet Explorer, la matriz HttpRequest.UserLanguages se rellena en orden de preferencia del usuario. El primer elemento de la matriz contiene el nombre de la referencia cultural o región primaria del usuario. Si la matriz contiene algún otro elemento, Internet Explorer le asigna arbitrariamente un especificador de calidad, que está delimitado del nombre de la referencia cultural mediante un punto y coma. Por ejemplo, una entrada para la referencia cultural fr-FR podría tener la forma fr-FR;q=0.7.
En el ejemplo, se llama al constructor CultureInfo con el parámetro useUserOverride establecido en false para crear un nuevo objeto CultureInfo. De este modo, tiene la seguridad de que si el nombre de la referencia cultural es el nombre de la referencia cultural predeterminada del servidor, el nuevo objeto CultureInfo creado por el constructor de clase contiene la configuración predeterminada de una referencia cultural y no refleja las configuraciones invalidadas con la aplicación Configuración regional y de idioma del servidor. Es poco probable que los valores de una configuración invalidada en el servidor permanezcan en el sistema del usuario o se reflejen en los datos proporcionados por el usuario.
Su código puede llamar al método Parse o TryParse del tipo numérico en el que se convertirá la entrada del usuario. Puede ser necesario llamar varias veces a un método de análisis en una única operación de análisis. Como resultado, el método TryParse resulta más conveniente porque devuelve false si se producen errores en una operación de análisis. Por el contrario, mantener un control sobre las excepciones repetidas que puede producir el método Parse puede ser una tarea excesivamente costosa cuando se trata de una aplicación web.
Compilar el código
Para compilar el código, cópielo en una página de código subyacente de ASP.NET para que reemplace todo el código existente. La página web de ASP.NET debe contener los controles siguientes:
Un control Label, al que no se hace referencia en código. Establezca la propiedad Text en "Escriba un número:".
Un control TextBox denominado NumericString.
Un control Button denominado OKButton. Establezca la propiedad Text en "Aceptar".
Cambie el nombre de la clase de NumericUserInput por el nombre de la clase definido por el atributo Inherits de la directiva Page de la página de ASP.NET. Cambie el nombre de la referencia del objeto NumericInput por al nombre definido en el atributo id de la etiqueta form de la página de ASP.NET.
Seguridad
Para evitar que un usuario inserte el script en la secuencia HTML, los datos proporcionados por el usuario nunca deberían devolverse directamente en la respuesta del servidor. En su lugar, deberían codificarse con el método HttpServerUtility.HtmlEncode.