Это хороший подход для временного изменения культуры текущего потока? - PullRequest
20 голосов
/ 26 апреля 2011

Я работаю над довольно большим приложением ASP .NET Web Forms, которое в настоящее время используется в основном в Соединенных Штатах.Мы находимся в процессе его развертывания в других частях мира, что, конечно, означает, что в настоящее время мы работаем над локализацией всех областей приложения.Вообще говоря, наш подход состоял в том, чтобы установить свойства CurrentCulture и CurrentUICulture текущего потока в начале каждого запроса для поддержки правильного форматирования и извлечения ресурсов на основе локали текущего пользователя.

В некоторых случаях, однако, мы имеемнеобходимость запуска определенного фрагмента кода с использованием культуры, отличной от культуры текущего пользователя.Например, «Пользователь А» живет в Германии, но работает на компанию, которая ведет бизнес с другими компаниями во Франции.Когда «Пользователь A» хочет создать счет-фактуру (PDF) для одной из этих французских компаний, мы хотим, чтобы этот код генерации счетов-фактур выполнялся с культурой «fr-FR», а не с культурой «de-DE».

Я рассмотрел несколько способов сделать это легко и мне интересно, правильно ли я это делаю.Мои основные проблемы связаны с производительностью и безопасностью потоков.

Один из подходов заключается в использовании статического метода, предназначенного для выполнения определенной задачи с предоставленной культурой.Примерно так:

 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;
        }
    }

Затем этот метод может быть вызван так:

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

Я также подумал о создании класса, который реализует IDisposable, который будет отвечать за установку потокакультура в его ctor, а затем возвращая исходные культуры обратно в метод Dispose, так что вы можете назвать это так:

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

Я все об этом говорю неправильно?Какой, если какой-либо из этих подходов предпочтительнее?

Ответы [ 2 ]

15 голосов
/ 26 апреля 2011

Мне нравится подход using. Я бы также создал метод расширения, чтобы все читалось лучше:

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

Примерно так:

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

Или, если это всегда ваш объект клиента, который устанавливает культуру, другой метод расширения повысил бы абстракцию еще дальше:

using (currentCustomer.CultureContext()) {
  invoiceService.CreateInvoice(currentCustomer.CustomerId);
}
2 голосов
/ 26 апреля 2011

Поскольку вы спрашиваете, является ли временное изменение культуры текущей темы хорошей идеей, я могу только ответить: нет .Это может быть использовано, если и только нет другого способа заставить вещи работать.Это потому, что такое переключение подвержено ошибкам.Хорошо, вы не забудете изменить ситуацию обратно с кодом, который дал вам Jordão (уважение), но ...
Пока у вас есть клиенты, которые хотят создавать французские счета.Я предполагаю, что вы хотите использовать французские форматы даты, числа и валюты.Это нормально.Но ... Что, если в будущем определенное будущее нужно будет распечатать в другом формате, например, на этом немецком языке?Собираетесь ли вы создать некрасивый обходной путь?

Я понимаю, что это может быть вне вашего контроля (например, программное обеспечение для составления отчетов может быть 3 rd сторонним автономным решением, и вы можетене контролируйте, как он обрабатывает ToString()), но если он находится под вашим контролем, я бы рекомендовал в первую очередь подавать данные в правильном формате.Например, вы можете создать слой преобразования данных (DTO) и правильно отформатировать данные (через ToString(IFormatProvider)).Я знаю, что это довольно трудоемко, но так как вы спрашиваете о правильном способе сделать что-то ...

Если бы мы были в одной организации, и я бы сделал обзор кода I18n, вы могли бы быть уверены, что я укажуВне временного изменения культуры как дефект.Обычно есть способ избежать этого.

...