У нас возникла странная проблема после переноса старого приложения (> 15 лет), написанного на c #, на новый Windows Server. Приложение использует OleDB для подключения к базе данных, которая является базой данных Informix. В этой базе данных есть таблица с текстами на нескольких языках. Приложение, работающее на сервере Windows 2003, работает нормально, однако в новой Windows 2016 возникает ошибка: «Значение данных не может быть преобразовано по причинам, отличным от несоответствия знака или переполнения данных. Например, данные были повреждены вхранилище данных, но строка все еще была извлекаема. "
После некоторого исследования мы обнаружили, что проблема заключается в строке, содержащей несколько символов Юникода.
Это часть текстаэто порождает проблему (только часть текста, иллюстрирующая проблему:
"17" -Leichtmetallräder ...... Ziffern - Schaltknauf "
Это текст на немецком языке и, кажется,Хорошо, проблема на самом деле с «-». Если посмотреть на запись в БД в шестнадцатеричном формате, то первый «-» кодируется как «3F», а второй тире кодируется как «C296», что соответствует U + 0096 (тире в Unicode)
Настройки для БД - en_US.819 (что соответствует ISO-8859-1 для поддержки всех языков, которые должны поддерживаться).
Теперь проблема в том, что при запуске программы в Windows 2003 результат записывается в файл правильно, например:
"17" -Leichtmetallräder ...... Ziffern - Schaltknauf "
Однако в Windows 2016 выше исключение возникает и ничего не пишется.
Я работал над некоторыми изменениями кода, первым делом я изменил OleDB для соединения Odbc, и исключение исчезло, однако текств выводе неверно:
"17" -Leichtmetallräder ...... Ziffern? Schaltknauf "
Обратите внимание, что один и тот же код с подключением odbc не может понять черту Unicode.
Это код OleDB, который работает в Windows 2003:
OleDbConnection ConnOleDbIDD = new OleDbConnection("Provider=Ifxoledbc.2;Data Source=db;INFORMIXSERVER=localhost;IFMX_UNDOC_B168163=1;");
string sConnectTemplateDB = "Data Source=SQLServerDB;Initial Catalog=DB1; Connect Timeout = 28800; Integrated Security=True";
ConnOleDbIDD.Open();
sExportSQL = "SELECT * From MyTable";
OleDbCommand cmdIDD = new OleDbCommand(sExportSQL, ConnOleDbIDD);
cmdIDD.CommandTimeout = 28800;
SqlDataAdapter da;
ConnSchemaIDD = new SqlConnection (sConnectTemplateDB);
ConnSchemaIDD.Open();
SqlCommand cmdSQLServerTemplate = new SqlCommand(sExportSQL.Replace("TRIM","LTRIM"), ConnSchemaIDD);
cmdSQLServerTemplate.CommandTimeout = 28800;
da = new SqlDataAdapter(cmdSQLServerTemplate);
OleDbDataReader dr;
DataSet ds = new DataSet();
da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
da.Fill(ds, sSourceTable);
DataTable dt = ds.Tables[sSourceTable];
dr = cmdIDD.ExecuteReader()
iEnCodingFrom = 1252;
iEnCodingTo = 1252;
while (dr.Read())
{
sValue = "";
sCurrentValue = "";
bDelimiterPosition = false;
foreach (DataColumn cCol in dt.Columns)
{
object oval = dr.GetValue(dr.GetOrdinal(cCol.ColumnName));
string val = Convert.ToString(dr[cCol.ColumnName]);
sCurrentValue = System.Text.Encoding.GetEncoding(iEnCodingTo).GetString(System.Text.Encoding.Convert(System.Text.Encoding.GetEncoding(iEnCodingFrom), System.Text.Encoding.GetEncoding(iEnCodingTo), System.Text.Encoding.GetEncoding(iEnCodingFrom).GetBytes(val)));
if (bDelimiterPosition == true)
{
sValue = sValue + sDelimiter + sCurrentValue.Trim();
}
else
{
sValue = sValue + sCurrentValue.Trim();
}
bDelimiterPosition = true;
}
w.WriteLine(sValue);
w.Flush();
}
dr.Close();
Предположим для этого примера, что «Mytable» имеет 2 столбца, первый - это целочисленный идентификатор, а второй - символ (3100).
Как вы видите, код делает некоторые странные вещи, такие как получение описания столбца изсхема таблицы в базе данных SQLServer и преобразование выходных данных БД из CP1252 в CP1252. Я не уверен, почему это было закодировано таким образом. Мой обходной путь для этой проблемы делал эти изменения в коде (используя вместо этого соединение odbcof oledb):
iEnCodingFrom = 28591;
...
sCurrentValue = Encoding.GetEncoding(iEnCodingTo).GetString(Encoding.GetEncoding(iEnCodingFrom).GetBytes(val.ToCharArray()));
...
Таким образом, изменив соединение с соединением ODBC на DB Informix, которое предотвращает возникновение исключения, и выполнив преобразование из кодовой страницы 28591 (8859-1) в 1252 (CP1252)выдает в Windows 2016 тот же результат, что и старый код в Windows 2013.
Так что у меня есть обходной путь, и я могу его использовать, однако яЯ хотел бы понять, почему это происходит, почему я не могу продолжать использовать OleDB и если есть способ заставить его работать в новой среде Windows (не работает также в Windows 10) без необходимости изменения кода.
Любая помощь будет принята с благодарностью.
Спасибо