Практическое руководство. Преобразование числовых данных, введенных пользователем в веб-элементах управления, в числа
Обновлен: Ноябрь 2007
Поскольку веб-страница может отображаться в любой части мира, пользователи могут вводить числовые данные в элемент управления TextBox, используя почти неограниченное число форматов. Поэтому очень важно определить языковой стандарт и региональные параметры пользователя веб-страницы. При разборе данных, введенных пользователем, можно применить соглашения форматирования, определенные языковым и региональными параметрами пользователя.
Преобразование входных числовых данных из веб-элемента управления TextBox в число
Определите, заполняется ли массив строк, возвращаемый свойством HttpRequest.UserLanguages. Если это не так, то перейдите к шагу 6.
Если массив строк, возвращаемый свойством UserLanguages заполнен, то извлеките его первый элемент. Первый элемент указывает на язык и регион по умолчанию или выбранный пользователем.
Создайте объект CultureInfo, представляющий выбранные пользователем региональные параметры, путем вызова конструктора CultureInfo.CultureInfo(String, Boolean).
Вызовите метод TryParse или метод Parse числового типа, к которому требуется преобразовать введенные пользователем данные. Используйте перегрузку метода TryParse или Parse с параметром provider и передайте ему один из следующих объектов:
Объект CultureInfo, созданный на шаге 3.
Объект NumberFormatInfo, возвращаемый свойством NumberFormat объекта CultureInfo, созданного на шаге 3.
Если выполнить преобразование не удалось, повторите шаги со второго по четвертый для каждого оставшегося элемента в массиве строк, возвращаемого свойством UserLanguages.
Если преобразование по-прежнему не удается или массив строк, возвращаемый свойством UserLanguages пуст, произведите разбор строки с использованием инвариантных региональных параметров, которые возвращаются свойством CultureInfo.InvariantCulture.
Пример
Следующий пример представляет собой полную страницу фонового кода для веб-формы, в которой пользователю предлагается ввести числовое значение в элемент управления TextBox, после чего выполняется его преобразование в число. Это число затем удваивается и выводится с помощью тех же правил форматирования, что и исходные входные данные.
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));
}
}
}
Свойство HttpRequest.UserLanguages заполняется на основании имен региональных параметров, содержащихся в заголовках Accept-Language, включенных в HTTP-запрос. Однако не все обозреватели включают заголовки Accept-Language в свои запросы, кроме того, пользователи могут полностью запретить заголовки. В связи с этим при разборе данных, введенных пользователем, возникает необходимость иметь резервный набор региональных параметров. Обычно, резервный набор региональных параметров является инвариантным и возвращается свойством CultureInfo.InvariantCulture. Пользователи также могут ввести в Internet Explorer название языка и региональных параметров, которое они вводят в текстовое поле, а это создает вероятность того, что такое название может оказаться недопустимым. Всвязи с этим возникает необходимость обработки исключений при создании объекта CultureInfo.
При извлечении из HTTP-запроса, посланного Internet Explorer, массив HttpRequest.UserLanguages заполняется в порядке, определенном в пользовательских настройках. Первый элемент массива содержит название основного национального языка/региона пользователя. Если массив содержит другие элементы, то Internet Explorer произвольно назначит им спецификатор качества, который отделяется от имени региональных параметров точкой с запятой. Например, запись региональных параметров fr-FR может принять форму fr-FR;q=0.7.
В примере вызывается конструктор CultureInfo с параметром useUserOverride с настройкой falseдля создания нового объекта CultureInfo. В этом случае, если региональные параметры по умолчанию используются на сервере, то новый объект CultureInfo, созданный конструктором класса, содержит все региональные параметры по умолчанию и не зависит от настроек, заданных при помощи серверного приложения Язык и региональные параметры. Значения всех скорректированных настроек на сервере вряд ли появятся на компьютере пользователя или отразятся в данных, введенных пользователем.
Код может вызвать метод Parse или метод TryParse числового типа, к которому требуется преобразовать данные, введенные пользователем. Для отдельной операции разбора может потребоваться повторный вызов метода синтаксического анализа. В результате метод TryParse является более эффективным, поскольку он возвращает false при отказе операции синтаксического анализа. Напротив, обработка повторяющихся исключений, которые могут посылаться методом Parse, может быть слишком затратной для веб-приложений.
Компиляция кода
Чтобы скомпилировать код, скопируйте его в страницу фонового кода ASP.NET таким образом, чтобы он заменил весь существующий код. Веб-страница ASP.NET должна содержать следующие элементы управления:
Элемент управления Label, который не указан в коде. Присвойте его свойству Text значение "Введите число:".
Элемент управления TextBox с именем NumericString.
Элемент управления Button с именем OKButton. Присвойте его свойству Text значение "ОК".
Измените имя класса с NumericUserInput на имя класса, который определен атрибутом Inherits директивы Page страницы ASP.NET. Измените имя ссылки на объект NumericInput на имя, определенное атрибутом id тега form страницы ASP.NET.
Безопасность
Чтобы предостеречь пользователя от добавления сценария в поток HTML, вводимые пользователем данные никогда не должны непосредственно передаваться обратно в ответе сервера. Вместо этого они должны быть зашифрованы с помощью метода HttpServerUtility.HtmlEncode.