2011-04-26 18 views
17

Trabajo en una aplicación bastante grande ASP .NET Web Forms que actualmente se usa principalmente en los Estados Unidos. Estamos en proceso de lanzarlo a otras partes del mundo, lo que por supuesto significa que estamos trabajando en la localización de todas las áreas de la aplicación. En términos generales, nuestro enfoque ha sido establecer las propiedades CurrentCulture y CurrentUICulture del subproceso actual al comienzo de cada solicitud para admitir el formato adecuado y la extracción de recursos en función de la configuración regional del usuario actual.¿Es este un buen enfoque para cambiar temporalmente la cultura del hilo actual?

En algunos casos, sin embargo, tenemos la necesidad de ejecutar un cierto código usando una cultura que no sea la cultura del usuario actual. Por ejemplo, 'Usuario A' vive en Alemania, pero trabaja para una empresa que hace negocios con otras compañías en Francia. Cuando 'Usuario A' desea crear una factura (PDF) para una de esas compañías francesas, queremos que ese código de generación de factura se ejecute con la cultura 'fr-FR' en lugar de la cultura 'de-DE'.

He considerado un par de maneras de hacerlo fácilmente y me pregunto si estoy haciendo esto correctamente. Mis principales preocupaciones están relacionadas con el rendimiento y la seguridad de las secuencias.

Un enfoque implica un método estático diseñado para ejecutar una tarea determinada con una cultura proporcionada. Algo como esto:

public static void RunWithCulture(CultureInfo culture, Action task) 
    { 
     if (culture == null) 
      throw new ArgumentNullException("culture"); 

     var originalCulture = new 
            { 
             Culture = Thread.CurrentThread.CurrentCulture, 
             UICulture = Thread.CurrentThread.CurrentUICulture 
            }; 

     try 
     { 
      Thread.CurrentThread.CurrentCulture = culture; 
      Thread.CurrentThread.CurrentUICulture = culture; 
      task(); 
     } 
     finally 
     { 
      Thread.CurrentThread.CurrentCulture = originalCulture.Culture; 
      Thread.CurrentThread.CurrentUICulture = originalCulture.UICulture; 
     } 
    } 

Este método podría entonces ser invocada como esto:

var customerCulture = new CultureInfo(currentCustomer.Locale); 
CultureRunner.RunWithCulture(customerCulture,() => invoiceService.CreateInvoice(currentCustomer.CustomerId)); 

También he considerado la creación de una clase que implementa IDisposable que sería responsable de establecer la cultura de rosca en su ctor y luego regresar las culturas originales de vuelta en el método Dispose, por lo que se podría llamar así:

var customerCulture = new CultureInfo(currentCustomer.Locale); 
using(new CultureRunner(currentCustomer.Locale)) 
{ 
    invoiceService.CreateInvoice(currentCustomer.CustomerId); 
} 

¿Voy sobre todo mal? ¿Cuál de estos enfoques es preferible?

+2

Me gusta el enfoque 'using'. –

+0

el enfoque de uso es el mejor para mí también. –

Respuesta

13

Me gusta el enfoque using. También me gustaría crear un método de extensión para hacer las cosas leen mejor:

var customerCulture = new CultureInfo(currentCustomer.Locale); 
using (customerCulture.AsCurrent()) { 
    invoiceService.CreateInvoice(currentCustomer.CustomerId); 
} 

Algo como esto:

public static class CultureInfoExtensions { 
    public static IDisposable AsCurrent(this CultureInfo culture) { 
    return new CultureRunner(culture); 
    } 
} 

O, si siempre es el objeto cliente que establece la cultura, otro método de extensión levantaría la abstracción aún más:

using (currentCustomer.CultureContext()) { 
    invoiceService.CreateInvoice(currentCustomer.CustomerId); 
} 
+0

Puede agregar una muestra más genérica, ya que CultureRunner no está declarado. Necesito ejecutar un método usando una cultura diferente. ¿Puedes actualizar tu respuesta? – Pedro77

2

Vote por el delegado RunWithCulture acerque aquí.

No dudes en añadir las razones/enlaces a esta publicación de la wiki.

2

Dado que usted está preguntando si el cambio temporal de Current Thread's Culture es una buena idea, solo puedo responder: no. Podría usarse solo si no hay otra forma de hacer que las cosas funcionen. Eso es solo porque tal cambio es propenso a errores. De acuerdo, no olvidará cambiar las cosas con el código que Jordão (respect) le dio, pero ...
Por ahora, tiene clientes que desean crear facturas en francés. Suponiendo que quiera usar formatos franceses de fecha, número y moneda. Está bien. Pero ... ¿Qué pasaría si en el futuro cierto futuro necesitara imprimirse con otro formato, por ejemplo este alemán originario? ¿Vas a crear algún tipo de trabajo feo?

entiendo que podría ser fuera de su control (como informes del software podría ser 3 rd partido independiente solución y no se podía controlar cómo se está manejando ToString()), pero si está dentro de su control, lo recomiendo alimentar los datos en el formato correcto en primer lugar. Por ejemplo, podría crear una capa de transformación de datos (DTO) y formatear los datos correctamente (a través del ToString(IFormatProvider)). Sé que esto es todo un esfuerzo, pero ya que está preguntando sobre la forma correcta de hacer las cosas ...

Si estuviéramos en la misma organización y haría una revisión del código I18n, podría estar seguro de que señalaría temporalmente cambiando la cultura como un defecto. Por lo general, hay una forma de evitar esto.

+0

Gracias por la respuesta. Cuando dice "... dicha conmutación es propensa a errores" ¿quiere decir que puede llevar a un código que es difícil de mantener, o que este enfoque puede conducir a errores reales de tiempo de ejecución en la aplicación? –

+0

Además, una de las razones por las que no opté por utilizar el enfoque ToString (IFormatProvider) es que necesito algo más que los formatos correctos de fecha y número; También necesito extraer texto estático en los idiomas correctos de los archivos resx. Todavía no he encontrado una forma efectiva y segura de extraer un mensaje con el idioma actual, salvo cambiar la propiedad CurretUICulture en el hilo actual. –

+0

Por error, me refería a mantener. No debería causar errores en otras partes de la aplicación, al menos cuando recuerda volver a conectarlo. –

Cuestiones relacionadas