![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANYAAAA6CAYAAADMZafXAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEM0NzIyRTM2RDk5MTFFMzg5QUNEOTBDNDFFNTRBNDMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEM0NzIyRTQ2RDk5MTFFMzg5QUNEOTBDNDFFNTRBNDMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0QzQ3MjJFMTZEOTkxMUUzODlBQ0Q5MEM0MUU1NEE0MyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0QzQ3MjJFMjZEOTkxMUUzODlBQ0Q5MEM0MUU1NEE0MyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PrsyKkEAABiSSURBVHja7F0JmFTV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)
Здравствуйте друзья, коллеги.
В очередной раз решил с Вами поделиться рецептом исправления ошибки в движке BlogEngine.NET
Проблема
Настроив свой блог и начав создавать новые посты, я столкнулся на первый взгляд с непонятным "багом". Иногда в некоторых постах начали пропадать русские буквы в некоторых словах, а вместо них иногда появляться последовательности символов типа: ��.
Решение
В процессе дебага был обнаружен следующий код:
/// <summary>
/// The web resource filter.
/// </summary>
public class WebResourceFilter : Stream
{
#region Constants and Fields
/// <summary>
/// The _sink.
/// </summary>
private readonly Stream sink;
string HtmlOut;
...
/// <summary>
/// Initializes a new instance of the <see cref="WebResourceFilter"/> class.
/// </summary>
/// <param name="sink">
/// The sink stream.
/// </param>
public WebResourceFilter(Stream sink)
{
this.sink = sink;
HtmlOut = "";
}
...
/// <summary>
/// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
/// </summary>
...
public override void Write(byte[] buffer, int offset, int count)
{
// collect all HTML in local variable
var html = Encoding.UTF8.GetString(buffer, offset, count);
HtmlOut += html;
}
...
/// <summary>
/// Write stream to the client before closing.
/// </summary>
...
public override void Close()
{
...
// parse custom fields
HtmlOut = CustomFieldsParser.GetPageHtml(HtmlOut);
var outdata = Encoding.UTF8.GetBytes(HtmlOut);
sink.Write(outdata, 0, outdata.GetLength(0));
sink.Close();
}
...
}
Было установлено, что метод void Write(byte[] buffer, int offset, int count) неоднократно вызывается в процессе одного реквеста и и мало того, если пост большой, то и несколько раз на на один пост. В сумме с тем фактом, что в метод приходит массив байт, которые являются частью UTF-8 строки с символами выходящими за пределы ASCII и имеющими размер более одно байта (для локализованных блогов) - это и приводит к проявлению описанных артефактов.
Остановимся на этом месте подробнее.
UTF-8
Основная статья: UTF-8
UTF-8 — представление Юникода, обеспечивающее наилучшую совместимость со старыми системами, использовавшими 8-битные символы. Текст, состоящий только из символов с номером меньше 128, при записи в UTF-8 превращается в обычный текст ASCII. И наоборот, в тексте UTF-8 любой байт со значением меньше 128 изображает символ ASCII с тем же кодом. Остальные символы Юникода изображаются последовательностями длиной от 2 до 6 байт
Из этого следует, что все английские буквы, цифры, специальны символы в UTF-8 будут закодированы как и в ASCII и их размер будет 1 байт. Все остальные символы будут закодированы последовательностями с размером от 2-ух байт.
Пример. Буква "А" из Кириллицы будет закодирована двумя байтами HEX: 04 и 10:
![](/image.axd?picture=%2f2015%2f12%2fLetter.png)
Рис 1
Соответственно в контексте вышеупомянутого, может возникнуть ситуация, когда в метод void Write(byte[] buffer, int offset, int count) поступит массив байт UTF-8 последовательностей полученных при кодировании символов. Последними элементами этого массива могут быть первые байты последовательности символа с размером последовательности два и более байт. То есть в массиве будут не все, а только первые байты последовательности последнего символа.
Соответственно в выражение var html = Encoding.UTF8.GetString(buffer, offset, count); метод Encoding.UTF8.GetString не сможет правильно раскодировать буфер последовательностей символов. Скорей всего его последние байты будут представлять совсем другой символ или вообще никакого (в случае управляющих или не имеющих ассоциации с символом байт последовательности). Это касается и первых байты в буфере при следующем вызове void Write(byte[] buffer, int offset, int count), которые будут представлять оставшиеся байты последовательности последнего символа из предыдущего вызова. Подобное поведение скорей всего приведёт к появлению упомянутых артефактов.
![](/image.axd?picture=%2f2015%2f12%2fProblemDetails.png)
Рис 2
Как видно из рисунка, после первого вызова
void Write(byte[] buffer, int offset, int count) в HtmlOut будет указатель на строку: "Прих[EOT]", а после второго вызова в HtmlOut будет указатель на строку: "При[EOT]8ет", что после некоторых фильтраций и будет записано в Response. В результате эта строка вместе с остальным HTML уйдёт клиенту и скорей всего будет показано как: "При8ет", HEX код 04 (EOT) при рендеринге будет пропущен, так как является не печатаемым, а управляющим кодом.Надеюсь всё понятно.
Решение
Не долго думая, было решено переписать код так, что бы куски строк не декодировались по мере поступления, а их байты накапливались в неком буфере уровня объекта. И уже непосредственно при необходимости использования строки целиком - декодировались. Это позволило бы раскодировать строку полностью без возникновения артефактов. Так как последовательности всех символов строки, целиком находились бы в этом буфере.
Собственно вот то что получилось:
/// <summary>
/// The web resource filter.
/// </summary>
public class WebResourceFilter : Stream
{
#region Constants and Fields
/// <summary>
/// The _sink.
/// </summary>
private readonly Stream sink;
private IList<byte> htmlOutBytes = new List<byte>();
...
public WebResourceFilter(Stream sink)
{
this.sink = sink;
htmlOutBytes = new List<byte>();
}
...
public override void Close()
{
var htmlOutBytesArray = htmlOutBytes.ToArray();
var htmlOut = Encoding.UTF8.GetString(htmlOutBytesArray, Zero, htmlOutBytesArray.Length);
...
}
...
/// <summary>
/// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
/// </summary>
...
public override void Write(byte[] buffer, int offset, int count)
{
// collect all HTML in local variable
htmlOutBytes.AddRange(buffer.Skip(offset).TakeWhile((item, index) => index < count).ToArray());
}
...
}
Ссылки
Спасибо за внимание.
Хорошей Вам жизни и до новых встреч.