Почему .NET вдруг попытается выполнить сериализацию моего объекта в моем приложении ASP.NET?

Я запускаю веб-роль Azure в режиме Full IIS. Запросы разрешены с помощью пользовательской базовой проверки подлинности.

У меня есть класс MyAssembly.CustomIdentity, который наследуется от System.Security.Principal.GenericIdentity. Когда вызывается HttpApplication.AuthenticateRequest обработчик (OnEnter() код из ссылки выше), он выполняет проверки, затем создает экземпляр MyIdentity.CustomIdentity и назначает его HttpContext.Current.User. Затем фактический обработчик запросов ASP.NET получает этот объект и может использовать его для поиска того, для какого пользователя он предназначен.

Теперь все более или менее прекрасно работает в конфигурации по умолчанию, когда IIS работает под учетной записью NETWORK SERVICE. При запуске роли я перезапускаю пул приложений IIS под локальным пользователем (чтобы предоставить ему дополнительные привилегии). Теперь даже следующий код

public partial class Default : System.Web.UI.Page
{
 protected void Page_Load(object sender, EventArgs e)
 {
 bool isAvailable = Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.IsAvailable;
 }
}

выдаст различные исключения. Сначала он говорит, что не может сериализовать мой класс CustomIdentity (который я исправляю, добавляя атрибут Serializable), тогда он говорит, что не может загрузить сборку MyAssembly (которую я исправляю, обрабатывая событие AppDomain.AssemblyResolve).

То, что я не понимаю, - это то, почему сериализация срабатывает? Зачем запускать пул приложений под локальным пользователем и вызывать этот тривиальный код внезапно запускает сериализацию?

3 ответа

Будьте осторожны с этим ответом, так как я не совсем уверен, что это хороший.

Во-первых, я полагаю, вы не настроили что-то вроде управления сеансом sql, и единственное, что вы изменили, - это пользователь, под которым работает IIS.

Вы наблюдаете два явления:

  • Сериализация объекта, который не должен быть сериализован
  • Загрузка вашей сборки AppDomain, которая еще не загрузила ее.

Поскольку ваш appdomain уже загрузил сборку, кажется безопасным предположить, что исключение выбрано другим AppDomain. Если он был добавлен другим Appdomain, вероятно, потому, что этот AppDomain пытается десериализовать свой пользовательский объект. (Он был сериализован до того, как это продемонстрирует другое исключение.)

OK. Теперь, даже если IIS работает под локальным пользователем, роль Environmentne не является. Эта служба установлена ​​с Azure OS, вы не можете выбрать пользователя, с которым она работает (вы могли бы, вероятно, на самом деле, но я бы не стал)

Я думаю, что для получения информации от RoleEnvironnement среда выполнения Azure может использовать два пути кода:

  • Один, если служба IIS и Runtime работают под одним и тем же пользователем, что не требует переадресации доменов.
  • другой, если служба IIS и среда выполнения не используют пользователя, с которым они работают. В этом случае требуется время выполнения, поскольку у двух пользователей нет одинаковых прав.

В заключение, я, конечно, не знаю, почему среда выполнения Azure хотела бы переместить вашего пользователя между различными AppDomain, но это, вероятно, делает именно это.


ИЗМЕНИТЬ Перечитав свой вопрос, я не уверен, что это проблема. Я оставляю это здесь, потому что я потратил 5 минут на это, и это полезно.:) Если вы пишете веб-приложения, вам нужно знать о состоянии сеанса и вариантах хранения!

Как говорит Дэниел Пауэлл, очень вероятно, что вы храните экземпляр своего объекта в состоянии сеанса.

Приложения ASP.NET имеют 3 стандартных режима хранения состояния сеанса. InProc (in-process) хранит его в памяти, поэтому сериализация не требуется. StateServer или SqlServer будет пытаться сериализовать состояние сеанса либо на сервере состояния ASP.NET, либо на сервере SQL соответственно.

Чтобы убедиться, что это проблема, вам нужно будет проверить, что атрибут mode элемента sessionState находится в файле web.config.

Если вы используете SQL Server или State Server, ваше приложение будет сериализовать все состояние сеанса в конце каждого запроса. У вас есть несколько вариантов:

  • Измените состояние сеанса на InProc. Это предотвратит сериализацию, но вы не сможете использовать среду с балансировкой нагрузки. Кроме того, если ваше приложение перезагрузится, все пользователи потеряют свою сессию (поскольку она хранится в памяти).

  • Прекратите помещать этот объект в сеанс. Если вам не нужно хранить этот объект в сеансе, то не делайте этого! Проблема решена.

  • Сделать объект и любые дочерние его элементы сериализуемыми, реализуя ISerializable. Это невозможно, если объект использует "живые" элементы, такие как соединения с базой данных и т.д.


Связано ли это со следующей ошибкой подключения:

https://connect.microsoft.com/VisualStudio/feedback/details/712500/cant-use-appdomains-inside-wcf-called-methods

licensed under cc by-sa 3.0 with attribution.