XmlSerializer не использует XmlSerializers.dll, созданный sgen

В моем проекте Visual Studio 2010 я использую следующую командную строку события Post-Build, чтобы использовать sgen для создания XmlSerializers.dll.

Событие после сборки:

"$(ProgramFiles)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sgen.exe" /a:"$(TargetPath)" /c:/keyfile:"c:\myproject\mykey.snk" /f

У моего проекта строгое имя, поэтому используйте тот же ключ для строгого имени «XmlSerializers.dll». VS создает XmlSerializers.dll в выходной папке.

Однако я заметил, что при использовании ProcessMonitor .NET все еще вызывает CSC.exe во время выполнения. Я наткнулся на эту запись, где у пользователя была аналогичная проблема. и разрешается с помощью конструктора XmlSerializer (Type).

Я использовал ту же технику в своем коде, но он по-прежнему вызывает csc.exe:

var fs = new FileStream(SettingsFilePath, FileMode.Open);
try
{
var serializer = new XmlSerializer(typeof(AppSettings));
settings = (AppSettings)serializer.Deserialize(fs);
}
finally
{
fs.Close();
}

Причина, по которой мне нужно использовать предварительно скомпилированную сериализацию XML, из-за производительности, а также я иногда видел ошибки csc.exe при завершении работы Windows. Мое приложение сохраняет данные при закрытии формы, во время выключения происходит сбой, потому что Windows не позволяет запускать новый процесс во время завершения работы. Я видел рекомендации, как обойти это путем предварительной компиляции сериализации XML.

Любые предложения о том, почему XmlSerializer не использует XmlSerializers.dll, созданный sgen?

Спасибо.


person Din    schedule 09.05.2012    source источник
comment
Самое простое решение проблемы выключения - загрузка данных при запуске. Используйте fuslogvw.exe, чтобы проверить разрешение сборки.   -  person Hans Passant    schedule 09.05.2012
comment
Спасибо, мне нужно сохранить данные (сериализовать в XML), когда MainForm закроется. Во время нормального закрытия с пользователем все в порядке, ошибок нет, данные сериализованы. Однако, если мое приложение запущено и Windows завершается, я вижу ошибки CSC.exe.   -  person Din    schedule 10.05.2012


Ответы (3)


Возможно, проблема в другой целевой платформе: по умолчанию sgen использует 'Any CPU' (MSIL), если сборка, содержащая тип для десериализации или сериализации, скомпилирована для x86 или x64, она не будет загружать .XmlSerializers.dll

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

/// <summary>Generates an identifier for the assembly of a specified type</summary>
/// <remarks>Code copied from the .NET serialization classes - to emulate the same bahavior</remarks>
/// <param name="type">The type</param>
/// <returns>String identifying the type's assembly</returns>
static string GenerateAssemblyId(Type type) 
{ 
  Module[] modules = type.Assembly.GetModules();
  ArrayList list = new ArrayList();
  for (int i = 0; i < modules.Length; i++) {
    list.Add(modules[i].ModuleVersionId.ToString()); 
  }
  list.Sort(); 
  StringBuilder sb = new StringBuilder(); 
  for (int i = 0; i < list.Count; i++) {
    sb.Append(list[i].ToString()); 
    sb.Append(",");
  }
  return sb.ToString();
} // GenerateAssemblyId

/// <summary>Verifies that the serialization assembly for the specified type can be loaded</summary>
/// <remarks>Code copied from the .NET serialization classes - to emulate the same behavior and tests</remarks>
/// <param name="type">The type</param>
static void AssertCanLoadXmlSerializers(Type type)
{
  if (type == null)
    throw new ArgumentNullException("type");
  Assembly serializerAssembly = null;
  // Create the name of the XML serilizers assembly from the type's one
  AssemblyName name = type.Assembly.GetName(true); 
  name.Name = name.Name + ".XmlSerializers"; 
  name.CodeBase = null;
  name.CultureInfo = CultureInfo.InvariantCulture;
  try {
    serializerAssembly = Assembly.Load(name);
  } catch (Exception e) {
    Assert.Fail("Unable to load XML serialization assembly for type '{0}': {1}", type.FullName, e.Message);
  }
  object[] attrs = serializerAssembly.GetCustomAttributes(typeof(XmlSerializerVersionAttribute), false);
  if (attrs == null || attrs.Length == 0) {
    Assert.Fail(
      "Unable to use XML serialization assembly '{1}' for type '{0}': it does not contain XmlSerializerVersionAttribute", 
      type.FullName, 
      serializerAssembly.FullName
    );
  }
  if (attrs.Length > 1) {
    Assert.Fail(
      "Unable to use XML serialization assembly '{1}' for type '{0}': it contains multiple XmlSerializerVersionAttribute", 
      type.FullName, 
      serializerAssembly.FullName
    );
  }
  XmlSerializerVersionAttribute assemblyInfo = (XmlSerializerVersionAttribute)attrs[0];
  string assemblyId = GenerateAssemblyId(type);
  if (assemblyInfo.ParentAssemblyId != assemblyId) {
    Assert.Fail(
      "Unable to use XML serialization assembly '{1}' for type '{0}': it does not match assembly id '{2}'", 
      type.FullName, 
      serializerAssembly.FullName,
      assemblyId
    );
  }
} // AssertCanLoadXmlSerializers

просто вызовите AssertCanLoadXmlSerializers(), передав тип, который необходимо сериализовать / десериализовать. Если сборки сериализации не загружаются, вы можете понять причину этого по сообщениям об ошибках.

Я добавил его в наше модульное тестирование, чтобы быть достаточно уверенным, что сборки сериализации в порядке.

person MiMo    schedule 08.12.2012
comment
Этот код весьма полезен. Спасибо. Я пытаюсь понять, как исправить проблему, если утверждение не выполняется в последнем блоке (он не соответствует идентификатору сборки). Не могли бы вы объяснить, что это значит и как это исправить? - person Oren Hizkiya; 13.08.2015
comment
Прошло какое-то время ... идентификатор сборки состоит из номеров версий модулей в этой сборке, если они разные, это будет означать, что две сборки (одна, содержащая тип, а другая для сериализации) состоят из разных модули - или разные версии одних и тех же модулей - так что, вероятно, что-то изменится после создания сборки сериализации? Глядя на идентификаторы, вы должны понять, в чем разница - person MiMo; 13.08.2015

Вы пробовали запустить ngen. exe на сгенерированную dll?

Бег

ngen.exe install myproject.XmlSerializers.dll

установит собственный образ dll в кеш изображений, который следует использовать во время выполнения, а не вызывать JIT-компилятор.

person tgriffin    schedule 09.05.2012
comment
Спасибо, я попробовал ваше предложение об использовании ngen.exe, но все еще вижу вызовы cse.exe в ProcessMonitor. - person Din; 10.05.2012
comment
Вот снимок экрана ProcessMonitor: screencast.com/t/iyKu79yv DataSerializer.XmlSerializers.dll - это созданная dll сериализатора пользователя sgen. - person Din; 10.05.2012

Вы уверены, что сборка сериализации правильно подписана? Обычно кавычки нужно избегать. Дополнительную информацию см. здесь.

Вы также можете проверить, совпадают ли идентификаторы. Если вы измените исходную сборку после сборки сборки сериализации, идентификаторы больше не будут совпадать, и сборка сериализации не будет использоваться. Дополнительную информацию см. здесь.

Если все верно: Отключите Инструменты -> Параметры -> Отладка -> «Включить только мой код» и включите Отладку -> Исключения -> Исключения среды CLR -> Выброшено. Затем отладьте свое приложение до момента, когда сериализация будет выполнена. Будет выброшено исключение первого шанса, указывающее, почему сборка сериализации не может быть использована.

person cremor    schedule 13.02.2013