Mikhail Filippov's Blog

My personal blog.

Загрузка больших файлов в Media для Umbraco CMS

Перейти к готовому примеру web.config

Недавно столкнулся со с проблемой в Umbraco CMS. С настройками по умолчанию не получалось загружать файлы больше 30Мб. Причем выглядит это крайне странно полоска загрузки файл пробегает окно загрузки закрывается, при этом файл не появляется. При это никаких ошибок не возникает. Обычно проблемы с загрузкой больших файлов решается установкой в web.config настройки максимальной длины запроса:

web.config
1
<httpRuntime requestValidationMode="2.0" maxRequestLength="1024000" executionTimeout="3600" />

Но это не помогло.

Попытаемся разобраться в чем же дело. Для начала посмотрим что происходит при загрузке файла. Для этого запустим Fiddler и попытаемся проанализировать весь процесс.

  • Нажимаем кнопку загрузить файл: Нажимаем загрузить файл
  • Выбираем файл и нажимаем кнопку Upload: Выбираем файл
  • Видим что пошла нормальная загрузка: Пошла загрузка
  • После окончания загрузки окно закрывается без ошибок и предупреждений но файл на появляется. Файл не появился
  • Откроем окно загрузки повторно: Повторное октрытие
  • Тут мы видим что полоска загрузки красная похоже произошла какая-то ошибка. Посмотрим что в этот момент происходило в Fiddler. Происходит странное, в момент обращения к обработчику MediaUploader.ashx выдается ошибка 404, при этом в случае загрузки небольшого файла такого не происходит. Повторное октрытие
  • После долгих поисков я нашел параметр который отвечает за настройку фильтрации максимальному размеру поля Content-Legth в запросе. Для его изменения открываем IIS Manager(Его можно поменять и из web.config как я опишу ниже). Открывает настройки нашего сайта и выбираем “Request Filtering”: ISS Manager
  • На панели действий выбираем “Edit Feature Settings…”: Edit Feature Settings
  • Меняем значение поля Maximum allowed content length на большее например дописываем пару нулей :), обратите внимание что размер значения в байтах: Change Settings
  • В web.config проверяем что в httpRuntime стоит правильно значение maxRequestLength без этого работать не будет!
  • Пробуем повторно загрузить файл: Change Settings
  • Все работает корректно

Чтобы все это настроить без IIS Manager

В секции system.web и system.webServer файла web.config нужно добавить следующие параметры (ограничение размера 1Гб):

web.config
1
2
3
4
5
6
7
8
9
10
11
12
<configuration>
  <system.web>
      <httpRuntime requestValidationMode="2.0" maxRequestLength="1024000" executionTimeout="3600" />
  </system.web>
  <system.webServer>
      <security>
      <requestFiltering>
          <requestLimits maxAllowedContentLength="1024000000" />
      </requestFiltering>
    </security>
  </system.webServer>
</configuration>

Как открыть VHD образ виртуальной машины в Parallels Desktop 8

Я часто сталкиваюсь с необходимостью развертывания различных виртуальных машин на своем ноутбуке. В этом мне всегда помогает Parallels Desktop 8. Это хороший продукт, который очень тесно интегрирован в мою основную ОС Mac OS X. Отдельные типа виртуальных машин PD8 умеет конвертировать при открытии, то есть достаточно выполнить комманду File->Open и выбрать файл с настройками виртуальной машины. Этот способ работает для VMWare и VirtualBox, когда у вас есть файл с настройками машины.

Недавно мне понадобилось развернуть несколько триальных версий Windows Server 2012 для тестирования. Ставить их из ISO образов очень не хотелось. Благо у Microsoft доступны готовые предустановленные образы виртуальных машин в формате VHD. Только вот незадача PD8 никак не хотел делать из такого образа машину. Немного погуглив я нашел способ как это сделать.

Для начала скачаем файл образ машины: 9200.16384.amd64fre.win8_rtm.120725-1247_server_serverstandardeval_en-us.vhd.

Кладем его в отдельную папку и рядом с ним создаем файл: “Windows Server 2012.vmc” со следующем содержимым:

Windows Server 2012.vmc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
  <preferences>
      <version type="string">2.0</version>
      <hardware>
          <pci_bus>
              <ide_adapter>
                  <ide_controller id="0">
                      <location id="0">
                          <drive_type type="integer">1</drive_type>
                          <pathname>
                              <absolute type="string">/Path-To-VHD-Folder/9200.16384.amd64fre.win8_rtm.120725-1247_server_serverstandardeval_en-us.vhd</absolute>
                              <relative type="string">9200.16384.amd64fre.win8_rtm.120725-1247_server_serverstandardeval_en-us.vhd</relative>
                          </pathname>
                      </location>
                  </ide_controller>
              </ide_adapter>
          </pci_bus>
      </hardware>
</preferences>

Теперь открываем этот файл в PD8 File->Open:

Открываем файл

PD8 предложит конвертировать машину:

Начало конвертации

Указываем папку куда положить конвертированную машину и запускаем процесс:

Процесс конвертации

После завершения конвертиции можно сразу запустить машину. Но мне необходимо запустить несколько таких машин, по этому превращу машину в шаблон. Когда после конвертации PD8 спросит нужно ли запустить машину для завершения конвертации выбираем No.

No

Выбираем File->Convert To Template:

Convert to template

После этого закрываем машину и у нас в списке машин появляется готовый шаблон. Делаем из этого шаблона рабочую машину:

Развертывание Куда развертывать

Теперь можно запустить развернутую машину она при этом продолжит конвертацию:

Продолжение конвертации

Через некоторое время машина попросит сделать дополнительные настройки:

Дополнительные настройки

Проходим шаги мастера настройки ОС и входим в систему. После этого автоматически установятся Parallels Tools машина перезагрузится и конвертация будет завершена.

Завершение

Шаблон для Windows Server я специально сделал до первого запуска, потому что при этом у каждой виртуальной машины будет свой собственный SID и они смогут нормально работать в одном домене Active Directory. Если этого не сделать, а сразу запустить машину и довести конвертацию до конца, не получится ввести две виртуальных машины в один домен так как у них будут одинаковые SID.

Обзор облака из коробки.

Последние несколько месяцев проходило тестирование облака от компании InfoBox. Хотелось бы поделится впечатлениями о данном решение.

Облако InfoBox построено на основе контейнерной виртуализации от компании Parallels. Есть возможность выбора контейнера как на основе Linux так и на основе Windows. В качестве Linux дистрибутива предлагается Debian 6.0 x86_64. В качестве Windows: Server 2008 R2.

Интерфейс управления облаком InfoBox выглядит достаточно не плохо и в целом позволяет быстро разобраться с ним даже не подготовленному пользователю. При создании машин есть 3 предопределенных профиля: Basic, Power и Mega. Вот пример настроек доступных при создании виртуальной машины: Создание виртуальной машины Есть одна интересная особенность не забудьте выбрать пропускную способность. Шейпер у инфобокс работает очень хорошо, я сначала не понял почему так сильно тормозит сеть. Особенно это сильно заметно на RDP соединение у Windows машины. Эту настройку можно будет поменять после того как машина будет создана.

В работе с сетью есть несколько особенностей. Во первых у клиента есть возможность использовать как публичные так и приватные адреса. То есть вы можете создать приватную сетевую инфраструктуру и сделать себе 1 точку входа в нее. Во вторых можно создать один или несколько преднастроенных балансировщиков нагрузки HTTP, которые можно сразу назначить на уже созданные сервера. Еще одно особенностью является то что исходящий траффик платный. Для тестирования производительности сети я установил на сервер SpeedTest Mini. Вот результат теста при том что в настройках сетевого подключения стоит ограничение 100 КБит/сек:

Тест сети 100КБит/сек

А вот при ограничение в 50МБит/сек:

Тест сети 50МБит/сек

Как видим полоса пропускания соответствует заявленной. Из веб-интерфейса так же можно управлять настройками брандмауэра: Создание правила брандмауэра Чтобы оценить примерные затраты на использование облака, по каждому серверу можно просмотреть расход ресурсов и примерную стоимость: Расход ресурсов Так же можно помотреть расход ресурсов по всей инфраструктуре в пункте “Использование всех ресурсов”: Использование всех ресурсов На учетной записи есть общие лимиты которые действуют суммарно на всю инфраструктуру их можно просмотреть в пункте меню “Ресурсы подписки”: Ресурсы подписки Из веб-панели всегда можно сбросить пароль для доступа к машине при этом новый пароль Вам вышлют на почту на которую зарегистрирован аккаунт.

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

Для автоматизации облака доступен API PACI с помощью удобного REST интерфейса вы можете написать различные скрипты автоматизации работы облака.

Из общих моментов InfoBox так же предлагает дополнтельный услуги такие как управление и регистрация доменов и SSL-сертификаты. По итогам тестирования особых проблем с работой облака я не заметил. Иногда были некоторые подтормаживания веб-интерфейса управления, но в целом все работает не плохо. Еще из минусов не нашел возможности делегирования управления на дополнительные учетные записи например если у вас в компании несколько системных администраторов и вы бы хотели делегировать управление частью сервером им, все работает под одной учетной записью, но я думаю при производственном внедрении InfoBox сможет решить эту проблемы. Отдельно хотелось бы заметить наличие контейнеров с Windows Server, я их пробывал в первый раз, оказалось вполне достойное решение.

Вы можете сами все это потрогать достаточно пройти по адресу http://www.infobox.ru/cloud/servers/ и заказать себе тестовый доступ, там же вы можете получить дополнительную информацию и задать свои вопросы онлайн-консультанту.

Тестирование с помощью Microsoft Fakes

В Visual Studio 2012 получил развитие один из продуктов Microsoft Researсh известный под именем Moles. Это mock-фреймворк для облегчения написания юнит-тестов. Моки это специальные объекты заглушки, с помощью которых в реализуют части функциональности приложения, которые необходимы тестируемому методу. Это дает возможность тестировать только логику метода определив статическую логику для его зависимостей.

В .NET существует популярный mock-фреймвок: Moq, но он не позволяет мокировать статические методы. Это является достаточно серьезной проблемой, когда вы тестируете код который зависит к примеру от текущей даты или файловой системы. Проблема заключается в следующем. Предположим у Вас есть код который регистрирует время входа пользователя в систему:

AccountManager.csСсылка на статью
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class AccountManager
{
    private List<string> _logs = new List<string>();

    public void SignIn(string user)
    {
        _logs.Add(string.Format(CultureInfo.InvariantCulture, "{0} {1} Sign In", DateTime.Now, user));
    }

    public IList<string> GetLogs()
    {
        return _logs;
    }
}

Напишем тест на метод SignIn:

AccountManagerTests.csСсылка на статью
1
2
3
4
5
6
7
8
9
10
11
[TestClass]
public class AccountManagerTests
{
    [TestMethod]
    public void ShouldBeCorrectLogRecordAfterSignIn()
    {
        var mgr = new AccountManager();
        mgr.SignIn("user1");
        Assert.AreEqual("02/03/2001 01:02:03 user1 SignIn", mgr.GetLogs().Last());
    }
}

Здесь мы сталкиваемся с проблемой тест не проходит потому, что в коде функции используется статическое свойство DateTime.Now, которое всегда выдает текущую дату и время и нет способа указать ей что надо возвращать какое-то предопределенное значение.

До появления Fakes можно было поступить так. Сделать хелпер класс который бы отвечал за обертывание вызова DateTime.Now и передать его в конструктор объекта.

Рассмотрим какие возможности предоставляет нам Microsoft Fakes. В Fakes существует два способа мокирования объектов: Stub и Shim. Они имееют разную реализацию и используются для решения различных типов задач.

  1. Stubs предназначены для мокирования интерфейсов и виртуальных методов не sealed классов. Эту функциональность предоставляют и другие тестовые фреймворки и работает достаточно быстро, потому что основанна на наследовании.

  2. Shims предназначены для мокирования статических, не переопределяемых методов, а также встроенных системных типов. Эта функциональность уникальна для Fakes и позволяет избежать создания множества оберток для сокрытия системных типов. Shims основаны на перезаписи кода в рантайме, и работают достаточно медленно. Давайте посмотрим как использовать обе эти технологии.

Для начала рассмотрим Stubs. Продолжим предыдущий пример. Для выноса из класса AccountManager зависимости DateTime, создадим новый интерфейс IDateTime, который будет определять 1 метод Now(), возвращающий текущую дату и время:

IDateTime.csСсылка на статью
1
2
3
4
public interface IDateTime
{
    DateTime Now();
}

Добавим в основной проект его реализацию:

DateTimeHelper.csСсылка на статью
1
2
3
4
5
6
7
public class DateTimeHelper : IDateTime
{
    public DateTime Now()
    {
        return DateTime.Now;
    }
}

Изменим AccountManager так, чтобы он принимал реализацию интерфейса в конструкторе и использовал её для получения текущего времени:

AccountManager.csСсылка на статью
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class AccountManager
{
    private readonly IDateTime _dateTime;
    private List<string> _logs = new List<string>();

    public AccountManager(IDateTime dateTime)
    {
        _dateTime = dateTime;
    }

    public void SignIn(string user)
    {
        _logs.Add(string.Format(CultureInfo.InvariantCulture, "{0} {1} Sign In",
                                _dateTime.Now(), user));
    }

    public IList<string> GetLogs()
    {
        return _logs;
    }
}

Теперь перепишем тест с использованием Stubs, для этого для начала нужно сгенерировать Stubs. Нажмем правой кнопкой на сборку к которой мы хотим получить Stub. И выберем: Add Fakes Assembly.

How to generate Stubs.

После этого у нас появятся сгенерированные Stubs для всех классов сборки. И файл с расширением .fakes с настройками кодогенерации. Теперь в тесте мы можем использовать сгенерированный Stub.

AccountManagerTests.csСсылка на статью
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[TestClass]
public class AccountManagerTests
{
    [TestMethod]
    public void ShouldBeCorrectLogRecordAfterSignIn()
    {
        var stub = new StubIDateTime { Now = () =>

                    new DateTime(2001, 02, 03, 01, 02, 03, DateTimeKind.Local) };
        var mgr = new AccountManager(stub);
        mgr.SignIn("user1");
        Assert.AreEqual("02/03/2001 01:02:03 user1 Sign In", mgr.GetLogs().Last());
    }
}

Запустим тест и видим что он нормально проходит. Stub так же можно использовать для мокирования свойств:

test.csСсылка на статью
1
2
3
4
5
6
7
8
interface IMyInterface {
    int Value { get; set; }
}

var stub = new StubIMyInterface();
int i = 5;
stub.ValueGet = () => i;
stub.ValueSet = (value) => i = value;

Дополнительную информацию о Stubs можно получить в MSDN.

Теперь рассмотрим Shims. В тестовом проекте интерфейс IDateTime служит исключительно для того чтобы была возможность подменить вызов DateTime.Now, давайте посмотрим как с этим справится Shim. Для начала удалим интерфейс и его реализацию, затем вернем на место вызов DateTime.Now.

AccountManager.csСсылка на статью
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AccountManager
{
    private List<string> _logs = new List<string>();

    public void SignIn(string user)
    {
        _logs.Add(string.Format(CultureInfo.InvariantCulture,

                                 "{0} {1} Sign In", DateTime.Now, user));
    }

    public IList<string> GetLogs()
    {
        return _logs;
    }
}

Видим что тест перестал проходить. Теперь добавим в тест изменение поведения DateTime.Now с помощью Shims. Для начала сделаем Add Fakes Assembly для сборки System, это обеспечит генерацию Shim для класса DateTime, а за тем перепишем код теста:

AccountManagerTests.csСсылка на статью
1
2
3
4
5
6
7
8
9
10
11
12
[TestMethod]
public void ShouldBeCorrectLogRecordAfterSignIn()
{
    using (ShimsContext.Create())
    {
        ShimDateTime.NowGet = () => new DateTime(2001, 02, 03, 01, 02, 03,
DateTimeKind.Local);
        var mgr = new AccountManager();
        mgr.SignIn("user1");
        Assert.AreEqual("02/03/2001 01:02:03 user1 Sign In", mgr.GetLogs().Last());
    }
}

Запустим тест и видим, что он проходит. Shim позволяет подменять функциональность любых закрытых методов и избавляет нас от необходимости делать кучу ненужных оберток. Опишу подробнее, что происходит. Все вызовы к DateTime.Now внутри блока using (ShimsContext.Create()) будут перехвачены и подменены mock-объектом. Mock-контекст существует только в рамках этого блока. Дополнительно об использование Shims вы можете почитать в MSDN.

Подведем итоги Microsoft Fakes представляет собой Mock-фреймворк интегрированный в Visual Studio 2012 и позволяющий сильно упростить написание тестов на платформе .NET.

P.S. Если кому-то интересны какие-то особенности Fakes пишите комментарии постораюсь ответить.