Diskuze: MVC Session životnost na serveru
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 23 zpráv z 23.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Životnost session lze ovlivnit přes nastavení php, konkrétně session.gc_maxlifetime a session.cookie_lifetime.
Zkus si zkontrolovat, jestli tam nejsou nějaké nestandardní hodnoty, default je 1440 a 0.
Mám to napsané v C# a jak jsem psal, na lokále ta samá aplikace funguje.
Jak píše Dan, zkontroluj nastavení ISS položku časový limit relace. Na lokále pracuješ s jiným serverem, který může mít jiné nastavení než ten webhostingový.
Je třeba si uvědomit, jak se Session data ukládají. Obecně: pro
uložení dat je potřeba místo (RAM/disk/DB/...). Pokud ukládáš mnoho dat,
potřebuješ mnoho místa.
Nepíšeš, jak Sessions ukládáš (In-process memory nebo nějaké perma
úložiště). Předpokládám, že in-process memory.
Může docházet k tomu, že pokud požaduješ příliš RAM, IIS recykluje
pooly - tzn. shodí starou aplikaci/process a nahodí novou.
Taky nepíšeš, zda se session "ztratí" vždy po stejné době nebo nahodile
(z pohledu času).
Další věcí je LoadBalancing - pokud aplikaci provozuješ na více serverech,
musíš sessions sdílet. Je asi jasné, že si servery navzájem do pamětí
nevidí.
OT: pro veřejný web bych se sessions vyhnul. Vhodná náhrada může být JWT.
Jak píše @zelvicek, server jednou za stanovený čas nebo po určitém
eventu recykluje aplikační pool.
In-process memory na webhostingu vůbec nepoužívej. Ideální je pro tebe
uložiště na SQLServer, nebo StateSterver. Informace v session pak přežijí
restart aplikace i serveru a dají se sdílet i v rámci více serverů.
Nastavuje se ve Web.config:
<system.web>
<sessionState mode=" SQLServer" allowCustomSqlDatabase="true" sqlConnectionString="tvůj connection string" />
</system.web>
Má to ale malý háček, informace, které do session ukládáš se musejí dát serializovat nebo musejí být označeny atributem Serializable.
Tady máš odkaz na návod jak to nastavit pro ukládání do SQL DB
Uhh promiň, vůbec mi nedocvaklo podívat se na kategorii automaticky jsem bral
PHPčko
SQLServer uložiště se mi povedlo rozběhnout na lokále, super, ale nevím jak nakonfigurovat SQL server na webhostingu. Systémovou databázi tempdb tam sice mají, ale neobsahuje tabulky ASPStateTempApplications, ASPStateTempSessions. Zkrátka nevím jak tam dostat ty potřebné věci. Mužeš mi poradit.
Ty 2 tabulky nemusí být v tempDB, můžeš je mít i ve své DB, . Důležitá je i údržba tabulky ASPStateTempSessions, dokáže docela rychle nabobtnat. Stačí v ní mazat exspirované řádky - sessiony (where [Expires] < getdate())
Tak už jsem to rozběhl, co se týče ukládání Session na SQL všude. Při změně InProc na SQLServer mi ale přestávají fungovat AJAX. Volám jim ActionResult v Controlleru a až po
...
Session["cart"] = cart;
return Json(cart, JsonRequestBehavior.AllowGet);
to jede stejně. Verze InProc to vrátí zpět do AJAX a dá se s tím dál
pracovat, ale verze SQLServer se do AJAX už nevrátí.
Zkoušel jsem serializovat třídy, s kterými to souvisí, ale nic se
nezměnilo.
Session s tím souviset nebude, co ti přiletí zpět do prohlížeče v
odpovědi na ten ajax?
Nejsou jinak pojmenovaný pole, velikost písmen, vím že si json serializer v
MVC dokáže dělat s názvy co chce
Problém je v tom, že do Session ukládám něco takového:
List<EshopItem> cart = new List<EshopItem>();
cart.Add(new EshopItem { Product = productModel.find(id), Quantity = quantity });
Session["cart"] = cart;
Všechny třídy, kterých se to dotklo jsem označil [Serializable()], ale ničemu to nepomohlo.
Vyhazuje to výjimku, nebo pak zdánlivě v sessioně nic není?
V Session je vše uloženo, na SQL se to taky tváří, že něco zapsal, ale jak jsem psal dříve, nevrátí mi příkaz:
return Json(cart, JsonRequestBehavior.AllowGet);
hodnoty zpátky do pohledu.
Ok, v konzoli prohlížeče v sekci síť sedí odpověď serveru s očekáváním? Nevidím totiž žádný důvod proč by to nemělo vrátit data...
Právě v té odpovědi mám chybu. Pokud v controlleru nepoužívám ukládání do Session mám:
Status Code: 200 OK
Response Headers
Content-Type: applications/json; cahrset=utf--8
Jakmile odblokuju ukládání do Session:
Status Code: 500 Internal Server Error
Response Headers
Content-Type: text/html; cahrset=utf--8
Nevím jak se vypořádat s tím Content -Type, což je jediný rozdíl.
Ještě mi to píše:
Stav relace nelze serializovat. V režimu StateServer a SQLServer bude
technologie ASP.NET serializovat objekty stavu relace, a v důsledku toho nejsou
objekty bez možnosti serializace nebo objekty MarshalByRef povoleny. Stejné
omezení platí v případě, že je podobná serializace provedena vlastním
úložištěm stavu relace v režimu Custom.
[SerializationException: Typ System.Data.Entity.DbContext v sestavení EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 není označen jako serializovatelný.]
Jasně… To znamená že nemáš všechny své vlastní třidy, které se ukládají do Sessiony, označené atributem [Serializable]
Projdi všechny třídy které se mohou dostat do session zda mají atribut [Serializable], resp. všechny své třídy/modely opatři atributem [Serializable].
List<EshopItem> cart = new List<EshopItem>();
cart.Add(new EshopItem { Product = productModel.find(id), Quantity = quantity });
Session["cart"] = cart;
Označil jsem třídy/modely [Serializable], ale chyba přetrvávala.
Tak jsem zkusil testovat od základů co projde. Nakonec jsem dospěl k vytvoření třídy stejné jako EshopItem(stejné vlastnosti, bez metod) a s ní to prošlo. Takže problém je někde v těch metodách.
A všechny vlastní třídy, které jsou jako property ve třídě EshopItem jsou taky označeny Serializable?
Konečně jsme se někam pohli - a stačilo uvést konkrétní chybu.
Předpokládám, že
productModel.find(id)
načítá data z DB pomocí EF.
Zkus si vypsat
productModel.find(id).GetType().AssemblyQualifiedName
. Myslím, že budeš překvapen.
Problém vyřešen, všechny vlastní třídy byly označeny Serializable, ale celé to blokoval řádek v rámci třídy EshopItem pro DBContext, což nebylo nutné tam mít.
private EshopDBEntities db = new EshopDBEntities();
Třída EshopDBEntities je public partial a měl jsem ji také označenou Serializable, ale přesto to nefungovalo. Nevím jestli by šlo její serializování vyřešit nějak jinak, ale já ji inicializuji v controlleru a do metody ve třídě EshopItem ji předávám jako parametr. Každopádně díky za pomoc.
Zobrazeno 23 zpráv z 23.