Исключительные сообщения на английском?

298

Мы регистрируем любые исключения, которые происходят в нашей системе, записывая сообщение Exception.Message в файл. Однако они написаны в культуре клиента. И турецкие ошибки не имеют большого значения для меня.

Итак, как мы можем регистрировать любые сообщения об ошибках на английском без изменения культуры пользователей?

Карра
источник
8
Почему вы не можете сделать это так: CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ("en"); // бросаем новое исключение здесь => Культура на английском Thread.CurrentThread.CurrentCulture = oldCulture;
CheGueVerra
93
Я не знаю разработчика, который рад за неанглийские сообщения об исключениях: S ..
Zéiksz
3
@ Zéiksz Посмотрите за пределы англоязычных стран, и вы найдете много из них: D. Проблема не в неанглийском тексте, проблема в языке, который вы не можете понять. Сообщения на вашем родном языке (при условии правильного перевода) в порядке.
Алехандро
31
@Alejandro Необходимость переводить сообщение об исключении с одного родного языка на английский, чтобы гуглить, - это еще большая боль в заднице. по моему мнению.
Антуан Мельцхайм
18
У какого идиота из Microsoft возникла идея переводить сообщения об ошибках, предназначенные только для разработчиков. Даже термины, которые используются в языке программирования как ключ в словаре, переводятся. (Ключ не найден в словаре становится Sleutel в niet gevonden в de bibliotheek на голландском языке). Я не хочу менять язык ОС для этого ...
Рол

Ответы:

66

Эту проблему можно частично обойти. Код исключения Framework загружает сообщения об ошибках из своих ресурсов в зависимости от текущей локали потока. В случае некоторых исключений это происходит во время доступа к свойству Message.

За этими исключениями вы можете получить полную версию сообщения на английском и американском языках, кратко переключив языковой стандарт потока на en-US во время его регистрации (предварительно сохраняя исходный языковой стандарт пользователя и восстанавливая его сразу после этого).

Делать это в отдельном потоке еще лучше: это гарантирует отсутствие побочных эффектов. Например:

try
{
  System.IO.StreamReader sr=new System.IO.StreamReader(@"c:\does-not-exist");
}
catch(Exception ex)
{
  Console.WriteLine(ex.ToString()); //Will display localized message
  ExceptionLogger el = new ExceptionLogger(ex);
  System.Threading.Thread t = new System.Threading.Thread(el.DoLog);
  t.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
  t.Start();
}

Где класс ExceptionLogger выглядит примерно так:

class ExceptionLogger
{
  Exception _ex;

  public ExceptionLogger(Exception ex)
  {
    _ex = ex;
  }

  public void DoLog()
  {
    Console.WriteLine(_ex.ToString()); //Will display en-US message
  }
}

Однако, как правильно указывает Джо в комментарии к предыдущей редакции этого ответа, некоторые сообщения уже (частично) загружаются из языковых ресурсов на момент выдачи исключения.

Это относится к части «параметр не может быть пустым» сообщения, сгенерированного, например, при возникновении исключения ArgumentNullException («foo»). В этих случаях сообщение все равно будет отображаться (частично) локализованным даже при использовании приведенного выше кода.

Помимо использования непрактичных хаков, таких как запуск всего кода, не относящегося к пользовательскому интерфейсу, в потоке с локализацией en-US, для начала, кажется, мало что можно сделать с этим: в коде исключений .NET Framework нет средства для переопределения локали сообщения об ошибке.

MDB
источник
10
Ваш пример работает для исключения FileNotFoundException, поскольку ресурс сообщения извлекается при обращении к свойству Message, а не при возникновении исключения. Но это не относится ко всем исключениям (например, попробуйте выбросить новое ArgumentNullException ("paramName"))
Джо
3
Я смущен. Я попытался следовать вашему ответу и проверить его, я хотел, чтобы мое исключение было на французском, поэтому я сделал, t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");и t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");все же, полученное исключение было на английском ...
VitalyB
7
@VitalyB Локализованные тексты исключений являются частью языковых пакетов .NET Framework. Таким образом, если у вас не установлен французский языковой пакет, вы не получите переведенные тексты.
Даниэль Роуз,
7
По крайней мере, в .NET 4.5 создаются все исключения, Environment.GetResourceString("...")поэтому ваше решение больше не работает. Лучше всего создать пользовательское исключение с собственным (английским) текстом сообщения и использовать свойство InnerException, чтобы сохранить старое.
webber2k6
1
Отражение для получения имен типов исключений может стать удобным.
Гильермо Пранди
67

Вы можете найти оригинальное сообщение об исключении на unlocalize.com.

user461128
источник
5
Пробовал искать некоторые китайские сообщения об исключениях, всегда говорил мне No records found.
Тайлер Лонг,
1
Плохой выбор. Когда я отправляю свои исключения в Google Analytics (или другой облачный сервис), у меня будут разные группы исключений для одного и того же исключения, но на разных языках. И я не смогу сортировать по количеству каждого исключения, потому что оно не отражает реальное количество (100 на английском, 77 на китайском, 80 на корейском ... и т. Д.)
Artemious,
Я не забываю найти этот прекрасный веб-сайт много раз, когда я просто помещал в Google локализованные сообщения об исключениях, теперь он больше не доступен.
Мартин Браун
40

Возможно, спорный момент, но вместо того, чтобы установить культуру en-US, вы можете установить его на Invariant. В Invariantкультуре сообщения об ошибках на английском языке.

Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;

Он имеет преимущество в том, что не выглядит предвзятым, особенно для неамериканских англоязычных языков. (он же избегает грубых замечаний коллег)

MPelletier
источник
1
Где мы должны написать эти строки в нашем проекте ASP.NET? Спасибо.
Джейсон
2
Я собираюсь предложить наверху, в Application_Start. Это заставит весь проект работать на английском языке. Если вам нужны только сообщения об ошибках, вы можете создать функцию прикрытия и вызывать ее в каждом catch.
MPelletier
5
Разве это также не делает стандартные кнопки окна сообщений на английском языке? Это может быть нежелательным поведением.
Нергудс
12

Вот решение, которое не требует какого-либо кодирования и работает даже для текстов исключений, которые загружаются слишком рано, чтобы мы могли изменить их по коду (например, в mscorlib).

Это может быть не всегда применимо в каждом случае (это зависит от ваших настроек, так как вам нужно иметь возможность создавать файл .config помимо основного файла .exe), но это работает для меня. Итак, просто создайте app.configв dev (или a [myapp].exe.configили web.configin production), который содержит следующие строки, например:

<configuration>
  ...
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="mscorlib.resources" publicKeyToken="b77a5c561934e089"
                          culture="fr" /> <!-- change this to your language -->

        <bindingRedirect oldVersion="1.0.0.0-999.0.0.0" newVersion="999.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Xml.resources" publicKeyToken="b77a5c561934e089"
                          culture="fr" /> <!-- change this to your language -->

        <bindingRedirect oldVersion="1.0.0.0-999.0.0.0" newVersion="999.0.0.0"/>
      </dependentAssembly>

      <!-- add other assemblies and other languages here -->

    </assemblyBinding>
  </runtime>
  ...
</configuration>

Это говорит платформе о перенаправлении привязок сборки для mscorlibресурсов и System.Xmlресурсов, для версий от 1 до 999, на французском языке (культура установлена ​​в " fr") к сборке, которая ... не существует (произвольно версия 999).

Поэтому, когда CLR будет искать французские ресурсы для этих двух сборок (mscorlib и System.xml), он не найдет их и изящно переключится на английский. В зависимости от контекста и тестирования вы можете добавить другие сборки в эти перенаправления (сборки, содержащие локализованные ресурсы).

Конечно, я не думаю, что это поддерживается Microsoft, поэтому используйте на свой страх и риск. Ну, в случае, если вы обнаружите проблему, вы можете просто удалить эту конфигурацию и проверить, что она не связана.

Саймон Мурье
источник
1
Работает, когда требуется вывод на английский язык из инструментов тестирования бегуна.
Смг
Пробовал это, но у меня не получилось. Есть ли другие файлы ресурсов в .net? Где я могу их найти?
Блю
1
Посмотрите в c: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319. На каждом языке есть двухбуквенная папка. Не забудьте заменить «fr» в ответе выше реальным языком, который используется. «нет» для норвежского, «да» для датского, «св» для
шведского
Чтобы создать полный список, посмотрите в эту папку. Это около 120 файлов ресурсов. Добавьте каждый из них в конфиг. Похоже, что это пока единственное решение для Windows 10 и новее, поскольку больше нет возможности удалить языковые пакеты .Net в более новых окнах (это часть ОС). Теперь он даже помещен в GAC, поэтому удаление этих языковых папок, похоже, не работает.
Wolf5
10

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

В en-US windows 7 ultimate с установленным pt-PT следующий код:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("pt-PT");
string msg1 = new DirectoryNotFoundException().Message;

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
string msg2 = new FileNotFoundException().Message;

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
string msg3 = new FileNotFoundException().Message;

Производит сообщения в pt-PT, en-US и en-US. Поскольку файлы французской культуры не установлены, по умолчанию используется язык Windows по умолчанию (установлен?).

danobrega
источник
Это решило проблему. В моем случае польский пользовательский интерфейс установил языковые пакеты en MUI ~ 260MB, используя программу Vistalizator.
Кшиштоф Шинтер
5

Я знаю, что это старая тема, но я думаю, что мое решение может быть весьма уместным для любого, кто сталкивается с этим в веб-поиске:

В регистраторе исключений вы можете войти в ex.GetType.ToString, что позволит сохранить имя класса исключения. Я ожидаю, что имя класса должно быть независимым от языка и поэтому всегда будет представлено на английском языке (например, «System.FileNotFoundException»), хотя в настоящее время у меня нет доступа к системе иностранных языков для проверки идея.

Если вы действительно хотите получить текст сообщения об ошибке, вы можете создать словарь всех возможных имен классов исключений и их эквивалентных сообщений на любом языке, который вы предпочитаете, но для английского я думаю, что имя класса вполне подходит.

варвар
источник
5
Не работает Я получил InvalidOperationException, брошенный мимо System.Xml.XmlWellFormedWriter. Вы пытаетесь угадать, какая именно ошибка произошла, не читая сообщение. Может быть тысяча разных вещей.
Nyerguds
4
CultureInfo oldCI = Thread.CurrentThread.CurrentCulture;

Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ("en-US");
Thread.CurrentThread.CurrentUICulture=new CultureInfo("en-US");
try
{
  System.IO.StreamReader sr=new System.IO.StreamReader(@"c:\does-not-exist");
}
catch(Exception ex)
{
  Console.WriteLine(ex.ToString())
}
Thread.CurrentThread.CurrentCulture = oldCI;
Thread.CurrentThread.CurrentUICulture = oldCI;

Без РАБОТ.

Ткс :)


источник
ты забыл;
KansaiRobot
4

Настройка Thread.CurrentThread.CurrentUICultureбудет использоваться для локализации исключений. Если вам нужны два вида исключений (одно для пользователя, другое для вас), вы можете использовать следующую функцию для перевода сообщения об исключении. Он ищет в ресурсах .NET-библиотеки исходный текст, чтобы получить ключ ресурса, а затем вернуть переведенное значение. Но есть один недостаток, который я пока не нашел хорошего решения: сообщения, содержащие {0} в ресурсах, не будут найдены. Если у кого-то есть хорошее решение, я был бы благодарен.

public static string TranslateExceptionMessage(Exception ex, CultureInfo targetCulture)
{
    try
    {
        Assembly assembly = ex.GetType().Assembly;
        ResourceManager resourceManager = new ResourceManager(assembly.GetName().Name, assembly);
        ResourceSet originalResources = resourceManager.GetResourceSet(Thread.CurrentThread.CurrentUICulture, createIfNotExists: true, tryParents: true);
        ResourceSet targetResources = resourceManager.GetResourceSet(targetCulture, createIfNotExists: true, tryParents: true);
        foreach (DictionaryEntry originalResource in originalResources)
            if (originalResource.Value.ToString().Equals(ex.Message.ToString(), StringComparison.Ordinal))
                return targetResources.GetString(originalResource.Key.ToString(), ignoreCase: false); // success

    }
    catch { }
    return ex.Message; // failed (error or cause it's not smart enough to find texts with '{0}'-patterns)
}
Vortex852456
источник
Это не сработает, если исключение содержит отформатированный параметр.
Ник Берарди
Да, как я уже сказал: «Но есть одна слабость, которую я пока не нашел хорошего решения: сообщения, содержащие {0} в ресурсах, не будут найдены. Если у кого-то есть хорошее решение, я был бы признателен».
Vortex852456
3

.NET Framework состоит из двух частей:

  1. Сам фреймворк .NET
  2. Языковые пакеты .NET Framework

Все тексты (например, сообщения об исключениях, ярлыки кнопок в MessageBox и т. Д.) Написаны на английском языке в самой платформе .NET. Языковые пакеты имеют локализованные тексты.

В зависимости от вашей конкретной ситуации решение может состоять в том, чтобы удалить языковые пакеты (то есть сказать клиенту сделать это). В этом случае тексты исключений будут на английском языке. Однако обратите внимание, что весь другой текст, предоставляемый платформой, будет также английским (например, надписи кнопок на MessageBox, сочетания клавиш для ApplicationCommands).

Даниэль Роуз
источник
Спасибо!! Я нахожу ироничным, что диалог удаления происходит на языке пакета удаления, а не на местном языке. Примечание: языковые пакеты возвращаются каждые несколько месяцев. я не понял почему, но я предполагаю обновление / обновление
Choco Smith
@ChocoSmith При каждом обновлении .NET Framework через Центр обновления Windows языковой пакет снова устанавливается.
Даниэль Роуз
5
Попросить клиентов удалить языковые пакеты для их собственного языка не является жизнеспособным решением.
Нергудс
2

Я хотел бы представить один из этих подходов:

  1. Исключения только когда-либо читаются вами, то есть они не являются клиентской функцией, поэтому вы можете использовать жестко привязанные нелокальные строки, которые не изменятся при работе в турецком режиме.

  2. Включите код ошибки, например, в 0x00000001каждую ошибку, чтобы ее можно было легко найти в английской таблице.

morechilli
источник
9
Это не сильно поможет, когда они являются исключениями, создаваемыми внутренними компонентами .net framework . Вся эта проблема не относится к исключениям, которые вы бросаете сами; Очевидно , программист выбирает то , что сообщение включить с тех .
Нергудс
1

Основано на ответе Undercover1989, но учитывает параметры и случаи, когда сообщения состоят из нескольких строк ресурсов (например, исключений аргументов).

public static string TranslateExceptionMessage(Exception exception, CultureInfo targetCulture)
{
    Assembly a = exception.GetType().Assembly;
    ResourceManager rm = new ResourceManager(a.GetName().Name, a);
    ResourceSet rsOriginal = rm.GetResourceSet(Thread.CurrentThread.CurrentUICulture, true, true);
    ResourceSet rsTranslated = rm.GetResourceSet(targetCulture, true, true);

    var result = exception.Message;

    foreach (DictionaryEntry item in rsOriginal)
    {
        if (!(item.Value is string message))
            continue;

        string translated = rsTranslated.GetString(item.Key.ToString(), false);

        if (!message.Contains("{"))
        {
            result = result.Replace(message, translated);
        }
        else
        {
            var pattern = $"{Regex.Escape(message)}";
            pattern = Regex.Replace(pattern, @"\\{([0-9]+)\}", "(?<group$1>.*)");

            var regex = new Regex(pattern);

            var replacePattern = translated;
            replacePattern = Regex.Replace(replacePattern, @"{([0-9]+)}", @"${group$1}");
            replacePattern = replacePattern.Replace("\\$", "$");

            result = regex.Replace(result, replacePattern);
        }
    }

    return result;
}
январь
источник
1

У меня была такая же ситуация, и все ответы, которые я нашел здесь и в других местах, не помогали или не удовлетворяли:

Thread.CurrentUICultureИзменяет язык исключений .net, но это не для Win32Exception, которая использует ресурсы Windows , на языке самого интерфейса Windows. Поэтому мне так и не удалось напечатать сообщения Win32Exceptionна английском, а не на немецком языке, даже не используя, FormatMessage()как описано в
разделе Как получить Win32Exception на английском?

Поэтому я создал свое собственное решение, которое хранит большинство существующих сообщений об исключениях для разных языков во внешних файлах. Вы не получите очень точное сообщение на желаемом языке, но вы получите сообщение на этом языке, которое намного больше, чем вы получаете в настоящее время (это сообщение на языке, который вы, вероятно, не понимаете).

Статические функции этого класса могут выполняться в установках Windows с разными языками: CreateMessages()создает тексты, зависящие от культуры,
SaveMessagesToXML()сохраняет их в столько файлов XML, сколько языков создано или загружено,
LoadMessagesFromXML()загружает все файлы XML с сообщениями, зависящими от языка.

При создании файлов XML на разных установках Windows с разными языками у вас скоро появятся все нужные вам языки.
Возможно, вы можете создавать тексты для разных языков в 1 Windows, когда у вас установлено несколько языковых пакетов MUI, но я еще не проверял это.

Протестировано с VS2008, готов к использованию. Комментарии и предложения приветствуются!

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Threading;
using System.Xml;

public struct CException
{
  //----------------------------------------------------------------------------
  public CException(Exception i_oException)
  {
    m_oException = i_oException;
    m_oCultureInfo = null;
    m_sMessage = null;
  }

  //----------------------------------------------------------------------------
  public CException(Exception i_oException, string i_sCulture)
  {
    m_oException = i_oException;
    try
    { m_oCultureInfo = new CultureInfo(i_sCulture); }
    catch
    { m_oCultureInfo = CultureInfo.InvariantCulture; }
    m_sMessage = null;
  }

  //----------------------------------------------------------------------------
  public CException(Exception i_oException, CultureInfo i_oCultureInfo)
  {
    m_oException = i_oException;
    m_oCultureInfo = i_oCultureInfo == null ? CultureInfo.InvariantCulture : i_oCultureInfo;
    m_sMessage = null;
  }

  //----------------------------------------------------------------------------
  // GetMessage
  //----------------------------------------------------------------------------
  public string GetMessage() { return GetMessage(m_oException, m_oCultureInfo); }

  public string GetMessage(String i_sCulture) { return GetMessage(m_oException, i_sCulture); }

  public string GetMessage(CultureInfo i_oCultureInfo) { return GetMessage(m_oException, i_oCultureInfo); }

  public static string GetMessage(Exception i_oException) { return GetMessage(i_oException, CultureInfo.InvariantCulture); }

  public static string GetMessage(Exception i_oException, string i_sCulture)
  {
    CultureInfo oCultureInfo = null;
    try
    { oCultureInfo = new CultureInfo(i_sCulture); }
    catch
    { oCultureInfo = CultureInfo.InvariantCulture; }
    return GetMessage(i_oException, oCultureInfo);
  }

  public static string GetMessage(Exception i_oException, CultureInfo i_oCultureInfo)
  {
    if (i_oException == null) return null;
    if (i_oCultureInfo == null) i_oCultureInfo = CultureInfo.InvariantCulture;

    if (ms_dictCultureExceptionMessages == null) return null;
    if (!ms_dictCultureExceptionMessages.ContainsKey(i_oCultureInfo))
      return CreateMessage(i_oException, i_oCultureInfo);

    Dictionary<string, string> dictExceptionMessage = ms_dictCultureExceptionMessages[i_oCultureInfo];
    string sExceptionName = i_oException.GetType().FullName;
    sExceptionName = MakeXMLCompliant(sExceptionName);
    Win32Exception oWin32Exception = (Win32Exception)i_oException;
    if (oWin32Exception != null)
      sExceptionName += "_" + oWin32Exception.NativeErrorCode;
    if (dictExceptionMessage.ContainsKey(sExceptionName))
      return dictExceptionMessage[sExceptionName];
    else
      return CreateMessage(i_oException, i_oCultureInfo);
  }

  //----------------------------------------------------------------------------
  // CreateMessages
  //----------------------------------------------------------------------------
  public static void CreateMessages(CultureInfo i_oCultureInfo)
  {
    Thread oTH = new Thread(new ThreadStart(CreateMessagesInThread));
    if (i_oCultureInfo != null)
    {
      oTH.CurrentCulture = i_oCultureInfo;
      oTH.CurrentUICulture = i_oCultureInfo;
    }
    oTH.Start();
    while (oTH.IsAlive)
    { Thread.Sleep(10); }
  }

  //----------------------------------------------------------------------------
  // LoadMessagesFromXML
  //----------------------------------------------------------------------------
  public static void LoadMessagesFromXML(string i_sPath, string i_sBaseFilename)
  {
    if (i_sBaseFilename == null) i_sBaseFilename = msc_sBaseFilename;

    string[] asFiles = null;
    try
    {
      asFiles = System.IO.Directory.GetFiles(i_sPath, i_sBaseFilename + "_*.xml");
    }
    catch { return; }

    ms_dictCultureExceptionMessages.Clear();
    for (int ixFile = 0; ixFile < asFiles.Length; ixFile++)
    {
      string sXmlPathFilename = asFiles[ixFile];

      XmlDocument xmldoc = new XmlDocument();
      try
      {
        xmldoc.Load(sXmlPathFilename);
        XmlNode xmlnodeRoot = xmldoc.SelectSingleNode("/" + msc_sXmlGroup_Root);

        string sCulture = xmlnodeRoot.SelectSingleNode(msc_sXmlGroup_Info + "/" + msc_sXmlData_Culture).Value;
        CultureInfo oCultureInfo = new CultureInfo(sCulture);

        XmlNode xmlnodeMessages = xmlnodeRoot.SelectSingleNode(msc_sXmlGroup_Messages);
        XmlNodeList xmlnodelistMessage = xmlnodeMessages.ChildNodes;
        Dictionary<string, string> dictExceptionMessage = new Dictionary<string, string>(xmlnodelistMessage.Count + 10);
        for (int ixNode = 0; ixNode < xmlnodelistMessage.Count; ixNode++)
          dictExceptionMessage.Add(xmlnodelistMessage[ixNode].Name, xmlnodelistMessage[ixNode].InnerText);
        ms_dictCultureExceptionMessages.Add(oCultureInfo, dictExceptionMessage);
      }
      catch
      { return; }
    }
  }

  //----------------------------------------------------------------------------
  // SaveMessagesToXML
  //----------------------------------------------------------------------------
  public static void SaveMessagesToXML(string i_sPath, string i_sBaseFilename)
  {
    if (i_sBaseFilename == null) i_sBaseFilename = msc_sBaseFilename;

    foreach (KeyValuePair<CultureInfo, Dictionary<string, string>> kvpCultureExceptionMessages in ms_dictCultureExceptionMessages)
    {
      string sXmlPathFilename = i_sPath + i_sBaseFilename + "_" + kvpCultureExceptionMessages.Key.TwoLetterISOLanguageName + ".xml";
      Dictionary<string, string> dictExceptionMessage = kvpCultureExceptionMessages.Value;

      XmlDocument xmldoc = new XmlDocument();
      XmlWriter xmlwriter = null;
      XmlWriterSettings writerSettings = new XmlWriterSettings();
      writerSettings.Indent = true;

      try
      {
        XmlNode xmlnodeRoot = xmldoc.CreateElement(msc_sXmlGroup_Root);
        xmldoc.AppendChild(xmlnodeRoot);
        XmlNode xmlnodeInfo = xmldoc.CreateElement(msc_sXmlGroup_Info);
        XmlNode xmlnodeMessages = xmldoc.CreateElement(msc_sXmlGroup_Messages);
        xmlnodeRoot.AppendChild(xmlnodeInfo);
        xmlnodeRoot.AppendChild(xmlnodeMessages);

        XmlNode xmlnodeCulture = xmldoc.CreateElement(msc_sXmlData_Culture);
        xmlnodeCulture.InnerText = kvpCultureExceptionMessages.Key.Name;
        xmlnodeInfo.AppendChild(xmlnodeCulture);

        foreach (KeyValuePair<string, string> kvpExceptionMessage in dictExceptionMessage)
        {
          XmlNode xmlnodeMsg = xmldoc.CreateElement(kvpExceptionMessage.Key);
          xmlnodeMsg.InnerText = kvpExceptionMessage.Value;
          xmlnodeMessages.AppendChild(xmlnodeMsg);
        }

        xmlwriter = XmlWriter.Create(sXmlPathFilename, writerSettings);
        xmldoc.WriteTo(xmlwriter);
      }
      catch (Exception e)
      { return; }
      finally
      { if (xmlwriter != null) xmlwriter.Close(); }
    }
  }

  //----------------------------------------------------------------------------
  // CreateMessagesInThread
  //----------------------------------------------------------------------------
  private static void CreateMessagesInThread()
  {
    Thread.CurrentThread.Name = "CException.CreateMessagesInThread";

    Dictionary<string, string> dictExceptionMessage = new Dictionary<string, string>(0x1000);

    GetExceptionMessages(dictExceptionMessage);
    GetExceptionMessagesWin32(dictExceptionMessage);

    ms_dictCultureExceptionMessages.Add(Thread.CurrentThread.CurrentUICulture, dictExceptionMessage);
  }

  //----------------------------------------------------------------------------
  // GetExceptionTypes
  //----------------------------------------------------------------------------
  private static List<Type> GetExceptionTypes()
  {
    Assembly[] aoAssembly = AppDomain.CurrentDomain.GetAssemblies();

    List<Type> listoExceptionType = new List<Type>();

    Type oExceptionType = typeof(Exception);
    for (int ixAssm = 0; ixAssm < aoAssembly.Length; ixAssm++)
    {
      if (!aoAssembly[ixAssm].GlobalAssemblyCache) continue;
      Type[] aoType = aoAssembly[ixAssm].GetTypes();
      for (int ixType = 0; ixType < aoType.Length; ixType++)
      {
        if (aoType[ixType].IsSubclassOf(oExceptionType))
          listoExceptionType.Add(aoType[ixType]);
      }
    }

    return listoExceptionType;
  }

  //----------------------------------------------------------------------------
  // GetExceptionMessages
  //----------------------------------------------------------------------------
  private static void GetExceptionMessages(Dictionary<string, string> i_dictExceptionMessage)
  {
    List<Type> listoExceptionType = GetExceptionTypes();
    for (int ixException = 0; ixException < listoExceptionType.Count; ixException++)
    {
      Type oExceptionType = listoExceptionType[ixException];
      string sExceptionName = MakeXMLCompliant(oExceptionType.FullName);
      try
      {
        if (i_dictExceptionMessage.ContainsKey(sExceptionName))
          continue;
        Exception e = (Exception)(Activator.CreateInstance(oExceptionType));
        i_dictExceptionMessage.Add(sExceptionName, e.Message);
      }
      catch (Exception)
      { i_dictExceptionMessage.Add(sExceptionName, null); }
    }
  }

  //----------------------------------------------------------------------------
  // GetExceptionMessagesWin32
  //----------------------------------------------------------------------------
  private static void GetExceptionMessagesWin32(Dictionary<string, string> i_dictExceptionMessage)
  {
    string sTypeName = MakeXMLCompliant(typeof(Win32Exception).FullName) + "_";
    for (int iError = 0; iError < 0x4000; iError++)  // Win32 errors may range from 0 to 0xFFFF
    {
      Exception e = new Win32Exception(iError);
      if (!e.Message.StartsWith("Unknown error (", StringComparison.OrdinalIgnoreCase))
        i_dictExceptionMessage.Add(sTypeName + iError, e.Message);
    }
  }

  //----------------------------------------------------------------------------
  // CreateMessage
  //----------------------------------------------------------------------------
  private static string CreateMessage(Exception i_oException, CultureInfo i_oCultureInfo)
  {
    CException oEx = new CException(i_oException, i_oCultureInfo);
    Thread oTH = new Thread(new ParameterizedThreadStart(CreateMessageInThread));
    oTH.Start(oEx);
    while (oTH.IsAlive)
    { Thread.Sleep(10); }
    return oEx.m_sMessage;
  }

  //----------------------------------------------------------------------------
  // CreateMessageInThread
  //----------------------------------------------------------------------------
  private static void CreateMessageInThread(Object i_oData)
  {
    if (i_oData == null) return;
    CException oEx = (CException)i_oData;
    if (oEx.m_oException == null) return;

    Thread.CurrentThread.CurrentUICulture = oEx.m_oCultureInfo == null ? CultureInfo.InvariantCulture : oEx.m_oCultureInfo;
    // create new exception in desired culture
    Exception e = null;
    Win32Exception oWin32Exception = (Win32Exception)(oEx.m_oException);
    if (oWin32Exception != null)
      e = new Win32Exception(oWin32Exception.NativeErrorCode);
    else
    {
      try
      {
        e = (Exception)(Activator.CreateInstance(oEx.m_oException.GetType()));
      }
      catch { }
    }
    if (e != null)
      oEx.m_sMessage = e.Message;
  }

  //----------------------------------------------------------------------------
  // MakeXMLCompliant
  // from https://www.w3.org/TR/xml/
  //----------------------------------------------------------------------------
  private static string MakeXMLCompliant(string i_sName)
  {
    if (string.IsNullOrEmpty(i_sName))
      return "_";

    System.Text.StringBuilder oSB = new System.Text.StringBuilder();
    for (int ixChar = 0; ixChar < (i_sName == null ? 0 : i_sName.Length); ixChar++)
    {
      char character = i_sName[ixChar];
      if (IsXmlNodeNameCharacterValid(ixChar, character))
        oSB.Append(character);
    }
    if (oSB.Length <= 0)
      oSB.Append("_");
    return oSB.ToString();
  }

  //----------------------------------------------------------------------------
  private static bool IsXmlNodeNameCharacterValid(int i_ixPos, char i_character)
  {
    if (i_character == ':') return true;
    if (i_character == '_') return true;
    if (i_character >= 'A' && i_character <= 'Z') return true;
    if (i_character >= 'a' && i_character <= 'z') return true;
    if (i_character >= 0x00C0 && i_character <= 0x00D6) return true;
    if (i_character >= 0x00D8 && i_character <= 0x00F6) return true;
    if (i_character >= 0x00F8 && i_character <= 0x02FF) return true;
    if (i_character >= 0x0370 && i_character <= 0x037D) return true;
    if (i_character >= 0x037F && i_character <= 0x1FFF) return true;
    if (i_character >= 0x200C && i_character <= 0x200D) return true;
    if (i_character >= 0x2070 && i_character <= 0x218F) return true;
    if (i_character >= 0x2C00 && i_character <= 0x2FEF) return true;
    if (i_character >= 0x3001 && i_character <= 0xD7FF) return true;
    if (i_character >= 0xF900 && i_character <= 0xFDCF) return true;
    if (i_character >= 0xFDF0 && i_character <= 0xFFFD) return true;
    // if (i_character >= 0x10000 && i_character <= 0xEFFFF) return true;

    if (i_ixPos > 0)
    {
      if (i_character == '-') return true;
      if (i_character == '.') return true;
      if (i_character >= '0' && i_character <= '9') return true;
      if (i_character == 0xB7) return true;
      if (i_character >= 0x0300 && i_character <= 0x036F) return true;
      if (i_character >= 0x203F && i_character <= 0x2040) return true;
    }
    return false;
  }

  private static string msc_sBaseFilename = "exception_messages";
  private static string msc_sXmlGroup_Root = "exception_messages";
  private static string msc_sXmlGroup_Info = "info";
  private static string msc_sXmlGroup_Messages = "messages";
  private static string msc_sXmlData_Culture = "culture";

  private Exception m_oException;
  private CultureInfo m_oCultureInfo;
  private string m_sMessage;

  static Dictionary<CultureInfo, Dictionary<string, string>> ms_dictCultureExceptionMessages = new Dictionary<CultureInfo, Dictionary<string, string>>();
}

internal class Program
{
  public static void Main()
  {
    CException.CreateMessages(null);
    CException.SaveMessagesToXML(@"d:\temp\", "emsg");
    CException.LoadMessagesFromXML(@"d:\temp\", "emsg");
  }
}
Тобиас Кнаусс
источник
1
Он Thread.CurrentUICulture также меняет язык интерфейса, что делает его ужасным вариантом. Классическим примером являются кнопки Да / Нет / ОК / Отмена в окне сообщения.
Нергудс
0

Исключительные сообщения на английском языке

try
{
    ......
}
catch (Exception ex)
{
      throw new UserFriendlyException(L("ExceptionmessagesinEnglish"));
}

затем перейдите в папку Localization и поместите ее в projectName.xml и добавьте

<text name="ExceptionmessagesinEnglish">Exception Message in English</text>
Набиэль Хаксан
источник
-1

Вы должны регистрировать стек вызовов вместо просто сообщения об ошибке (IIRC, простое исключение. ToString () должна сделать это за вас). Отсюда вы можете точно определить, откуда возникло исключение, и, как правило, определить, какое это исключение.

Бранко Димитриевич
источник
3
Мы регистрируем сообщение и отслеживание стека. Но намного проще, если сообщение ясно.
Карра
-1

Переопределить сообщение об исключении в блоке перехвата, используя метод расширения. Убедитесь, что выброшенное сообщение получено из кода или нет, как указано ниже.

    public static string GetEnglishMessageAndStackTrace(this Exception ex)
    {
        CultureInfo currentCulture = Thread.CurrentThread.CurrentUICulture;
        try
        {

            dynamic exceptionInstanceLocal = System.Activator.CreateInstance(ex.GetType());
            string str;
            Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");

            if (ex.Message == exceptionInstanceLocal.Message)
            {
                dynamic exceptionInstanceENG = System.Activator.CreateInstance(ex.GetType());

                str = exceptionInstanceENG.ToString() + ex.StackTrace;

            }
            else
            {
                str = ex.ToString();
            }
            Thread.CurrentThread.CurrentUICulture = currentCulture;

            return str;

        }
        catch (Exception)
        {
            Thread.CurrentThread.CurrentUICulture = currentCulture;

            return ex.ToString();
        }
user3472484
источник
1
Как я уже говорил ... InvalidOperationException. Получайте удовольствие, выясняя, что это значит без самого сообщения. У нового экземпляра не будет волшебства.
Нергудс
-1

В целях ведения журнала некоторым приложениям может потребоваться получить сообщение об исключении на английском языке (помимо его отображения в обычном клиентском UICulture).

Для этой цели следующий код

  1. меняет текущую UICulture
  2. воссоздает брошенный объект Exception с использованием «GetType ()» и «Activator.CreateInstance (t)»
  3. отображает сообщение нового объекта исключения в новом UICuture
  4. и затем, наконец, меняет текущую UICulture обратно на более раннюю UICulture.

        try
        {
            int[] a = { 3, 6 };
            Console.WriteLine(a[3]); //Throws index out of bounds exception
    
            System.IO.StreamReader sr = new System.IO.StreamReader(@"c:\does-not-exist"); // throws file not found exception
            throw new System.IO.IOException();
    
        }
        catch (Exception ex)
        {
    
            Console.WriteLine(ex.Message);
            Type t = ex.GetType();
    
            CultureInfo CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
    
            object o = Activator.CreateInstance(t);
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = CurrentUICulture; // Changing the UICulture back to earlier culture
    
    
            Console.WriteLine(((Exception)o).Message.ToString());
            Console.ReadLine();
    
         }
Ron16
источник
1
это не гарантирует, что сообщение об исключении нового объекта будет таким же, как и у брошенного исключения. Это может быть совсем другое, и обычно это совершенно другое. Вот почему нам нужно сообщение об исключении.
Артемий,