Dan
спасибо за предоставленную репродукцию.
Прежде всего, консольный бегун работает иначе, чем бегуны TestDriven.NET и ReSharper. По сути, консольный исполнитель должен выполнить гораздо больше работы по настройке, поскольку он создает новый домен приложений (плюс конфигурация) для каждой выполняемой сборки. Это необходимо для загрузки файла .dll.config для вашей сборки спецификации.
Для каждой сборки создается два домена приложений:
- Первый AppDomain (
Console
) создан
неявно, когда mspec.exe
выполняется,
- второй домен приложений создается mspec.exe для сборки, содержащей спецификации (
Spec
).
Оба домена приложений связываются друг с другом через .NET Remoting: например, когда спецификация выполняется в Spec
AppDomain, она уведомляет Console
AppDomain об этом факте. Когда Console
получает уведомление, оно действует соответствующим образом, записывая информацию о спецификации в консоль.
Это взаимодействие между Spec
и Console
осуществляется прозрачно через .NET Remoting. Одним из свойств .NET Remoting является то, что некоторые свойства вызывающего домена приложений (Spec
) автоматически включаются при отправке уведомлений целевому домену приложений (Console
). Thread.CurrentPrincipal
это такая собственность. Подробнее об этом можно прочитать здесь: http://sontek.vox.com/library/post/re-iprincipal-iidentity-ihttpmodule-serializable.html
Контекст, который вы предоставляете, будет работать в Spec
AppDomain. Вы устанавливаете Thread.CurrentPrincipal
в Because
. После запуска Because
на домен приложений Console
будет отправлено уведомление. Уведомление будет включать ваш пользовательский MyPrincipal
, который получающий Console
AppDomain пытается десериализовать. Он не может этого сделать, поскольку не знает о вашей сборке спецификаций (поскольку он не включен в свой путь к приватному бину ).
Вот почему вы должны были поместить вашу спецификацию сборки в ту же папку, что и mspec.exe.
Есть два возможных решения:
- Получите
MyPrincipal
и MyIdentity
из MarshalByRefObject
, чтобы они могли принимать участие в кросс-доменной связи через прокси (вместо сериализации)
- Установить
Thread.CurrentPrincipal
временно Because
(текст необходим для работы форматирования - пожалуйста, игнорируйте)
Because of = () =>
{
var previousPrincipal = Thread.CurrentPrincipal;
try
{
Thread.CurrentPrincipal = new MyPrincipal(...);
SUT = new MyViewModel();
}
finally
{
Thread.CurrentPrincipal = previousPrincipal;
}
}
ReSharper, например, обрабатывает всю коммуникационную работу для нас. Repecharper Runner от MSpec может подключиться к существующей инфраструктуре (которая, AFAIK, не использует .NET Remoting).