Странное поведение при попытке получить тип по AssemblyQualifiedName во время выполнения - PullRequest
4 голосов
/ 17 мая 2011

Я получаю исключение FileLoadException при попытке десериализации типа с помощью NetDataContractSerializer :

Указанное имя сборки или кодовая база недопустимы.(Исключение из HRESULT: 0x80131047)

Эта ошибка не относится конкретно к сериализатору;попытка загрузить тип во время выполнения по его квалифицированному имени сборки приводит к той же ошибке.

Я подключил слушатель к событию AssemblyResolve , чтобы увидеть, что происходит:

ResolveEventHandler reh = (o, e) =>
{
    var tryGet = AppDomain.CurrentDomain.GetAssemblies()
                          .Where(x => x.FullName == e.Name).FirstOrDefault();
    if (tryGet != null)
        return tryGet;
    //EDIT:  Crap, the following line is a stupid bug STUPID!  Ignore!
    return Type.GetType(e.Name).Assembly;
};

using (var stream = System.IO.File.OpenRead(serializedObjectFilename))
{
    try
    {
        AppDomain.CurrentDomain.AssemblyResolve += reh;
        var ser = new NetDataContractSerializer();
        return ser.Deserialize(stream) as MyType;
    }
    finally
    {
        AppDomain.CurrentDomain.AssemblyResolve -= reh;
    }
}

Заглавное «странное поведение» можно увидеть отладкой через обработчик.Хотя tryGet никогда не является null (требуемая сборка, в данном случае, всегда загружается в домен приложений), операция всегда завершается ошибкой , если оставить ее себе. Другими словами, вызов Type.GetType(e.Name).Assembly приведет к созданию исключения FileLoadException. Редактировать: Я совмещал строгое имя сборки с именем, определенным сборкой, типа;пожалуйста, игнорируйте эту ошибку.По иронии судьбы, это не выдает другую ошибку, поэтому я не уловил этого, прежде чем задавать этот вопрос.

Еще один бит информации: Assembly.Load(e.Name) всегда возвращает действительную сборку.Я не уверен, почему это работает, в то время как метод, используемый за кулисами во время десериализации, терпит неудачу.

Fusion Log сообщает, что загрузчик пытается загрузить правильную сборку, но так как сборка не найдена в приватнойпуть к исполняемому файлу, он завершается ошибкой.

Почему выполняется попытка загрузить сборку, когда сборка уже загружена в домен приложений ??


Подробнее о ведении журнала Fusion ...

Я собрал всю загрузку сборки до и во время вызова метода, который вызывает исключение.Вот соответствующие журналы, в порядке создания:

  • Частичное связывание СБОЙ
    • Попытка загрузить сборку только по имени
    • Только проверка базы приложения
  • Частичное связывание через LoadFrom SUCCEEDED
    • Where-ref bind.Расположение указывает на то, где находится ссылка на файл
    • Я полагаю, что VS использует LoadFrom при загрузке ссылок в решении
  • Привязка строгого имени FAILED
    • Неизвестно, что вызвало эту попытку загрузки
    • Только проверял базу приложения

AFAICT, Visual Studio загружает сборку в домен приложения решения (ffs, я желаю Fusion Logзахватил домен приложения, в котором была предпринята попытка загрузки, в конце концов, он записывает вызывающую сборку).

После этого я звоню по десериализации.Результатом является один журнал в Fusion:

Результат привязки: hr = 0x80070002.Системе не удается найти указанный файл.

Снова Fusion пытается загрузить из базы приложения исполняемого файла его строгое имя.Одна хорошая вещь;он пытается загрузить из GAC, поэтому после развертывания I может не иметь такой же проблемы.Но я все еще не понимаю, почему сборка не может быть расположена в домене приложения.


Другие интересные вещи ...

Это вызывает вызов десериализации:

MyType test = new MyType ();
var serialized = Serializer.ToXml(test);
// the following line fails with a FileLoadException
var deserialized = Serializer.FromXml<MyType>(serialized);

, где ToXml и FromXml оба используют NetDataContractSerializer и Write / ReadObject.Сборка загружается на раннем этапе выполнения из каталога установки пакета, но NDCS по какой-то причине не хочет использовать сборку, как она обнаружена в AppDomain.Этот тест показывает, что не может быть проблем с управлением версиями.

1 Ответ

0 голосов
/ 17 мая 2011

Одна вещь, которую я нахожу странным в вашем коде, заключается в том, что здесь:

GetAssemblies().Where(x => x.FullName == e.Name)

e используется в качестве имени сборки, поскольку оно будет соответствовать Assembly.Name, поэтому не будет иметь имякласса / типа в нем, тогда здесь:

return Type.GetType(e.Name).Assembly;

e используется как полностью определенное имя типа сборки, которое, я думаю, будет содержать как имя класса / типа, так и имя сборки.

Это преднамеренно?


Редактировать:

Извините, я опубликовал этот ответ так же, как вы отредактировали свое сообщение и уловили ошибку самостоятельно...

...