InvalidCastException из сеанса StateServer

Сайт, который я написал, испытывает странную проблему, из-за которой он внезапно не распознает элементы, хранящиеся в сеансе, сразу после того, как я сделал какое-либо обновление кода. Я искал Stackoverflow / google / и т. Д. И вижу, что у некоторых людей такая же проблема, но нигде не может найти решения.

Вот что примерно происходит:

Если я добавляю товар в свою корзину, он сохраняет List<BasketItem> в сеансе. Если я затем сделаю обновление некоторого кода (не BasketItem), переменная сеанса все еще существует, но .NET, похоже, не думает, что это List<BasketItem>, хотя это определенно так.

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

Исключение составляют:

System.InvalidCastException: [A] System.Collections.Generic.List1[BasketItem] cannot be cast to [B]System.Collections.Generic.List1 [BasketItem]. Тип A происходит от «mscorlib, Version = 2.0.0.0, Culture = нейтральный, PublicKeyToken = b77a5c561934e089» в контексте «LoadNeither» в расположении «C: \ Windows \ assembly \ GAC_64 \ mscorlib \ 2.0.0.0__b77a5c561934e089 \ mscorlib.dll» . Тип B происходит от «mscorlib, Version = 2.0.0.0, Culture = нейтральный, PublicKeyToken = b77a5c561934e089» в контексте «LoadNeither» в расположении «C: \ Windows \ assembly \ GAC_64 \ mscorlib \ 2.0.0.0__b77a5c561934e089 \ mscorlib.dll» .

Я использую StateServer для состояния сеанса и запускаю ASP.NET 3.5 SP1, если это помогает.

Код, который я использую, приведен ниже:

// for setting the basket
List<BasketItem> basketItems = new List<BasketItem>();
Session["basket"] = basketItems;

// for getting the basket
List<BasketItem> basketItems = (List<BasketItem>)Session["basket"];

На данный момент я использую «as casting», поэтому я не ошибаюсь, но это означает, что корзина пользователя теряется при обновлении кода.

Любые советы будут высоко ценится!

Ваше здоровье

Тим


person Community    schedule 07.12.2011    source источник
comment
Интересно, относится ли это к двум разным типам BasketItem; Можете ли вы подтвердить: возможно ли, что это загружается при сохранении из одной версии сборки, а затем загрузке из другой версии сборки? Возможно, BasketItem поступает из двух разных сборок? Возможно ли, что у вас есть разные машины в одной ферме с разными версиями сборки, или, может быть, каждая машина строится независимо?   -  person Marc Gravell    schedule 07.12.2011
comment
(несколько раздражает то, что сообщение об ошибке сообщает нам о List<> вместо BasketItem, из-за чего трудно увидеть, может ли строка сказать нам что-то очевидное)   -  person Marc Gravell    schedule 07.12.2011
comment
Привет, отметка, что касается вашего первого комментария - да, я полагаю, .NET может загружать BasketItem из двух разных сборок. Каждый раз, когда в App_Code вносятся изменения, я думаю, что .NET перекомпилирует его в новую сборку.   -  person    schedule 07.12.2011
comment
это наверняка сработает.   -  person Marc Gravell    schedule 07.12.2011


Ответы (1)


Этот тип проблемы довольно распространен из-за того, как BinaryFormatter хранит данные базового типа, что может вызвать проблемы, если они не разрешаются до в точности того же BasketItem, что и у вас. в уме. Чаще всего это больно при смене версии вашего приложения / библиотеки или когда есть разные серверы с разными состояниями.

Мой сильный совет: не позволяйте ему использовать BinaryFormatter для хранения состояния! Это не очень дружелюбно к версиям как в этом отношении, так и в некоторых других вопросах внутри типа. Если это возможно, я призываю вас вместо этого рассмотреть надежные контрактные данные (что означает: практически все, кроме BinaryFormatter / NetDataContractSerializer). Примеры:

  • вы можете использовать JavaScriptSerializer и хранить базовые string данных
  • вы можете использовать XmlSerializer и хранить базовые string данных
  • если вам нужен двоичный файл, вы можете использовать protobuf-net и обработать byte[] данных

Тогда вы, очевидно, будете использовать вспомогательные методы для хранения / извлечения ваших данных, обычно с общими void Store<T>(string key, T object) и T Retreive<T>(string key), используя typeof(T) внутри по мере необходимости. Преимущество этого заключается в том, что сохраненные данные теперь нейтральны по отношению к какой-либо конкретной реализации и могут использоваться другими версиями вашего приложения (поскольку ничто не зависит от типа) и даже другими платформами (Java, php и т. Д.), Если это необходимо. .

Я понимаю, что это побочный шаг обойти проблему, а не прямое решение, но: оно работает.

person Marc Gravell    schedule 07.12.2011
comment
Спасибо за развернутый ответ! Мне нравится ваше предложение о сериализации класса BasketItem в Xml и сохранении его в виде строки в сеансе. Я не вижу, чтобы у .NET были какие-либо проблемы с этим, поэтому я определенно собираюсь попробовать! - person ; 07.12.2011