Не секрет, что многие предпочитают использовать UTF-8 как кодировку выходных HTML файлов web-приложения. Однако, использование этой кодировки в проекте на ASP.NET MVC может осложняться следующей проблемой: при создании видов (aspx/ascx) в Visual Studio вновь созданные файлы сохраняются в другой кодировке. Это зависит то ли от настроек компьютера то ли от кодировки соответствующих шаблонов. Приходится вручную открывать эти файлы и преобразовывать в UTF-8.
Но хуже всего — если на продакшн-сервер «просочатся» не-utf-8-шаблоны, то соответствующие области сайта будут отображать кракозябры вместо, например, русских букв. Когда над проектом работает большая команда, такая ситуация вполне возможна, потому что кто-нибудь из разработчиков может легко забыть изменить кодировку.
Один из способ не допустить проникновения чужеродной кодировки в продакшн-сервер — создать соответствующий интеграционный тест. Этот тест будет запускаться на CI-сервере каждый раз после сборки и, в случае провала, даст знать разработчикам о проблемных файлах.
Итак, тест должен делать следующее:
- Рекурсивно перебирать все файлы в папке Views.
- Проверять, кодирован ли каждый файл в UTF-8.
- Накапливать информацию обо всех файлах с врождебной кодировкой.
Отдельно следует отметить пункт 2. Известно, что нет универсального способа определения кодировки произвольного файла. Есть только методы, позволяющий предположить, что тот или иной файл сохранён в той или иной кодировке. Для случая UTF-8 эта унылая задача несколько облегчается — библиотека Utf8Checker сделает всё за нас. Utf8Checker по сути состоит из одного единственного файла с таким интерфейсом:
/// <summary>
/// Interface for checking for utf8.
/// </summary>
public interface IUtf8Checker
{
/// <summary>
/// Check if file is utf8 encoded.
/// </summary>
/// <param name="fileName"></param>
/// <returns>true if utf8 encoded, otherwise false.</returns>
bool Check(string fileName);
/// <summary>
/// Check if stream is utf8 encoded.
/// </summary>
/// <param name="stream"></param>
/// <returns>true if utf8 encoded, otherwise false.</returns>
bool IsUtf8(Stream stream);
}
Как видно, выделенный метод делает то, что нам нужно — проверяет, кодирован ли файл в UTF-8.
Итак, получившийся код теста:
[TestFixture]
public class EncodingTests
{
private const string VIEWS_ROOT_FOLDER =
"../../../НАЗВАНИЕ ПРОЕКТА/Views";
private static readonly IList<string> IgnoreDirectoryNames =
new[] {".svn"}; 4
private IUtf8Checker _utf8Checker = new Utf8Checker();
[Test]
public void TestAllViewsUtf8Encoded() 5
{
var errorFiles = new List<string>();
CheckFilesUtf8Encoded(VIEWS_ROOT_FOLDER, errorFiles);
if (errorFiles.Count > 0)
{
var messageBuilder = new StringBuilder();
foreach (var file in errorFiles)
{
messageBuilder.AppendLine("File {0} is not UTF-8 encoded!"
.FormatWith(file));
}
Assert.Fail(messageBuilder.ToString()); 6
}
}
private void CheckFilesUtf8Encoded(
string path,
List<string> errorFiles) 1
{
foreach (var file in Directory.GetFiles(path))
{
var isUtf8Encoded = _utf8Checker.Check(file); 2
if (!isUtf8Encoded)
{
errorFiles.Add(file); 3
}
}
foreach (var directory in Directory.GetDirectories(path))
{
var directoryName = new DirectoryInfo(directory).Name;
if (!IgnoreDirectoryNames.Contains(directoryName))
{
CheckFilesUtf8Encoded(directory, errorFiles);
}
}
}
}
Метод CheckFilesUtf8Encoded 1 рекурсивно перебирает все папки и для каждого файла проверяет его кодировку. Если кодировка не UTF-8 2, то путь добавляется в список «ошибочных» файлов 3. Чтобы не проводить проверку внутри папок системы контроля версий (в моём случае это папки .svn) определён список 4 имён, которые игнорируются.
Основной метод теста — TestAllViewsUtf8Encoded 5 накапливает имена фалов с неверной кодировкой, выводит сообщение 6 если такие файлы найдены.
В результате, после выполнения такого теста, в системе CI или просто в логах test-runner можно увидеть список не-utf видов.
