更新:2007 年 11 月
由于网页可以在世界上的任何地方显示,用户可能以近乎无限多的格式在 TextBox 控件中输入数值数据。因此,确定网页用户的区域设置和区域性就变得十分重要。在接下来的用户输入分析中,您可以应用由该用户的区域设置和区域性定义的格式化约定。
将 Web TextBox 控件中的数值输入转换为数字
- 确定由 HttpRequest.UserLanguages 属性返回的字符串数组是否已被填充。如果没有,请继续步骤 6。 
- 如果由 UserLanguages 属性返回的字符串数组已被填充,请检索它的第一个元素。第一个元素指示用户默认或首选的语言和区域。 
- 通过调用 CultureInfo.CultureInfo(String, Boolean) 构造函数实例化表示用户首选区域性的 CultureInfo 对象。 
- 对于要将用户输入转换为的数值类型,请调用其 TryParse 或 Parse 方法。使用 TryParse 或 Parse 方法(带有 provider 参数)的重载,并向其传递下面两项当中的任意一项: - 在步骤 3 中创建的 CultureInfo 对象。 
- 由在步骤 3 中创建的 CultureInfo 对象的 NumberFormat 属性返回的 NumberFormatInfo 对象。 
 
- 如果转换失败,请为由 UserLanguages 属性返回的字符串数组中剩余的每个元素重复步骤 2 到步骤 4。 
- 如果转换仍然失败,或由 UserLanguages 属性返回的字符串数组为空,请使用由 CultureInfo.InvariantCulture 属性返回的固定区域性分析字符串。 
示例
下面的示例是一个 Web 窗体的完整代码隐藏页,该窗体让用户在 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 属性由 HTTP 请求中包含的 Accept-Language 标头中所含的区域性名称来填充。但是,并非所有浏览器的请求中都包含 Accept-Language 标头,并且用户也可以完全禁止标头的显示。因此,在分析用户输入时,就需要使用回退区域性。通常情况下,回退区域性是由 CultureInfo.InvariantCulture 返回的固定区域性。用户也可以向 Internet Explorer 提供他们在文本框中输入的区域性名称,这样便可能出现区域性名称无效的情况。因此,在实例化 CultureInfo 对象时,必须使用异常处理。
当从 Internet Explorer 提交的 HTTP 请求中检索到 HttpRequest.UserLanguages 数组后,将按照用户的首选顺序对其进行填充。数组中的第一个元素包含用户主区域性/区域的名称。如果该数组还包含任何其他项,Internet Explorer 将随意为它们分配一个质量说明符,并用分号将其与区域性名称分隔开。例如,表示 fr-FR 区域性的项可能采用 fr-FR;q=0.7 形式。
该示例调用 CultureInfo 构造函数,调用时 useUserOverride 参数设置为 false,以创建新的 CultureInfo 对象。这样可确保,如果区域性名称为服务器上的默认区域性名称,则由该类构造函数创建的新 CultureInfo 对象将包含区域性的默认设置,并且不反映使用服务器的“区域和语言选项”应用程序重写的任何设置。服务器上任何已重写设置的值不可能存在于用户的系统上,也不会反映在用户输入中。
您可以在代码中调用要将用户输入转换为的数值类型的 Parse 或 TryParse 方法。在一次分析操作中,可能需要重复调用某个分析方法。因此,TryParse 方法更加适用,因为它可以在分析操作失败时返回 false。与此相比,Parse 方法可能会不断引发异常,在 Web 应用程序中,处理这些异常将是一种非常占用资源的做法。
编译代码
若要编译代码,请将其复制到 ASP.NET 代码隐藏页中,以便替换所有现有的代码。该 ASP.NET 网页应包含下列控件:
- 名为 NumericString 的 TextBox 控件。 
请将类名从 NumericUserInput 更改为由 ASP.NET 页的 Page 指令的 Inherits 属性所定义的类名。同时将 NumericInput 对象引用的名称更改为由 ASP.NET 页的 form 标记的 id 属性所定义的名称。
安全性
若要防止用户将脚本注入 HTML 流中,切勿在服务器响应中直接回送用户输入。而是应改用 HttpServerUtility.HtmlEncode 方法回送用户输入。