|
|
Vývoj webových aplikací ASP.NET
-
Pokud je v LinkButtonu "statické html", ASP.NET control a LinkButtonu změníme nějakou vlastnost, která se ukládá do ViewState, dojde po postbacku ke ztrátě obsahu LinkButtonu (je vyčištěna vlastnost Controls). Nahlášeno na connect včetně dema, jak chybu zreprodukovat. Workaround nemám, takže nezbývá, než v LinkButtonu nepoužívat vnitřní obsah – což je poměrně rozumný přístup :-).
|
-
Leckoho možná překvapí chování validátorů (RegularExpressionValidatoru, CompareValidatoru a dalších) v jednoduchém případě:
<asp:TextBox ID="MyTB" runat="server" /> <asp:RegularExpressionValidator ValidationExpression="\d+" ControlToValidate="MyTB" Text="x" runat="server" /> <asp:Button Text="OK" runat="server" />
Co se děje:
- hodnota "123" validátor aktivuje, vstup je validní
- hodnoty "123 " nebo " 123" validátor aktivují, vstup není validní
- hodnotu " " (white-space) validátor propustí, vstup je podle něj validní
- nepomáhá ani ValidationExpression="^\d+$", validátor se prostě neaktivuje
- hodnota "" (String.Empty) validátor neaktivuje, validátory nevalidují Empty vstupy
- white-space samotný je považován za Empty a validátory se tak vyjma RequiredFieldValidatoru ignorují (a CustomValidatoru, pokud má nastaveno ValidateEmptyText="true")
|
-
Jak jsem již popisoval v předchozím články, nevýhodou jinak šikovného mechanizmu Health Monitoringu je, že nesbírá chyby z aynchronních requestů a z webových služeb ASP.NET. Jak se vypořádat s prvním problémem u AJAX requestů bylo již naznačeno, podívejme se teď na problematiku webových služeb ASP.NET (.asmx). V zásadě jde opět o zachycení problémové výjimky a předání WebRequestErrorEvent.
SoapExceptionHealthMonitoringHandler (SoapExtension)
Elegantní metodou jak se dostat k odběru výjimek během zpracování webových služeb a jak je předávat mechanizmu Health Monitoringu je požití SoapExtension. Uvádím opět kód kolegy Jiřího Kandy (pomocná třída WebRequestErrorEventExt byla již definována v předchozím článku): /// <summary> /// V případě chyby ve zpracování web metody (webové služby) zajistí oznámení chyby health monitoringem. /// Pozor, toto nefunguje (a chyby healthmonitoringu tak nejsou oznamovány), /// pokud se webové služby testují v browseru!!! Pro testování nutno použít skutečného klienta webové služby (třeba service reference v konzolovce). /// </summary> public class SoapExceptionHealthMonitoringHandler : System.Web.Services.Protocols.SoapExtension { #region ProcessMessage public override void ProcessMessage(System.Web.Services.Protocols.SoapMessage message) { try { if ((message != null) && (message.Stage == SoapMessageStage.AfterSerialize)) { if (message.Exception != null) { Exception exception = message.Exception; if ((exception is SoapException) && (exception.InnerException != null)) { exception = exception.InnerException; } if ((exception is HttpUnhandledException) && (exception.InnerException != null)) { exception = exception.InnerException; } new WebRequestErrorEventExt(exception.Message, message, exception).Raise(); } } } catch // pokud by zde nedejbože došlo k nějaké další výjimce, tak ji zamaskujeme { // NOOP } } #endregion
#region GetInitializer public override object GetInitializer(Type serviceType) { return null; }
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute) { return null; } #endregion
#region Initialize public override void Initialize(object initializer) { } #endregion }
...a zapojení ve web.configu potom v elementu configuration/system.web/webServices:
<webServices> <soapExtensionTypes> <add type="MyNamespace.SoapExceptionHealthMonitoringHandler, MyAssembly" priority="0" group="0" /> </soapExtensionTypes> </webServices>A JE TO.
|
-
Health Monitoring je šikovný vestavěný mechanizmus ASP.NET pro sledování a hlášení problémových situací. Typicky je používán pro zápis výjimek aplikace do event-logu nebo jejich posílání mailem.
Slabinou Health Monitoringu je, že se neumí vypořádat s chybami vzniklými během asynchronních postbacků (AJAX) ani s chybami vzniklými v rámci webových služeb ASP.NET. Přesněji řečeno ASP.NET na tyto chyby nějak nepamatuje a neoznamuje je do web-events mechanizmu, na němž je Health Monitoring závislý.
Podívejme se nyní na cestu, jak doplnit do Health Monitoringu sledování chyb AJAXu, sledování chyb webových služeb ponechávám do samostatného článku. Jak již bylo naznačeno, jde o to, že potřebujeme doplnit chybějící oznamování chyb do web.events mechanizmu. Chyba vzniklá během asynchronního postbacku způsobí vyvolání události ScriptManager.AsyncPostBackError. Potřebujeme se tedy napojit na tuto událost s vlastní obsluhou a v ní chybu předat jako WebRequestErrorEvent.
AjaxHealthMonitoring control
Jedním z možných opakovaně použitelných elegantních řešení je vytvoření vlastního controlu, který se bude umisťovat do stránek stejně jako samotný ScriptManager, např. tedy v MasterPage. Uvádím zde kód kolegy Jirky Kandy, který se s tím vypořádal takto:
public class AjaxHealthMonitoring: Control { #region OnInit protected override void OnInit(EventArgs e) { base.OnInit(e);
ScriptManager scriptManager = ScriptManager.GetCurrent(Page); if (scriptManager == null) { throw new InvalidOperationException("Ve stránce nebyl nalezen ScriptManager, který je controlem AjaxHealthMonitoring vyžadován."); } scriptManager.AsyncPostBackError += new EventHandler<AsyncPostBackErrorEventArgs>(ScriptManager_AsyncPostBackError); } #endregion
#region ScriptManager_AsyncPostBackError /// <summary> /// Obsluha události AsyncPostBackError ScriptManageru. Zajistí vyvolání události health monitoringu. /// </summary> private void ScriptManager_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e) { if (e.Exception != null) { new WebRequestErrorEventExt(e.Exception.Message, this, e.Exception).Raise(); } } #endregion }Pro úplnost uvádím odvozenou podobou třídy WebRequestErrorEventExt:
public class WebRequestErrorEventExt : WebRequestErrorEvent { public WebRequestErrorEventExt(string message, object eventSource, Exception exception) : base(message, eventSource, WebEventCodes.WebExtendedBase + 999, exception) { } }Control se pak používá ve stránce stejně jako ScriptManager (do výstupního HTML kódu nic nerenderuje):
<asp:ScriptManager ScriptMode="Release" AllowCustomErrorsRedirect="true" runat="server" /> <havit:AjaxHealthMonitoring runat="server" />
|
-
ASP.NET ve výchozí konfiguraci bere při lokalizaci resources z .resx souborů umístěch ve Vaší webové aplikaci. Globální resources ze složky ~/App_GlobalResources/, lokální resources z podsložek ./App_LocalResources/ u jednotlivých stránek/controlů. Na resources pak lze přistupovat použitím syntaxe <%$ Resources: ... %> z markup kódu, popř. metodami GetGlobalResourceObject(), resp. GetLocalResourceObject(). Ke globálním resources pak ASP.NET ještě generuje do namespace Resources třídy pro jednotlivé .resx soubory s properties odpovídajících jednotlivým klíčům (záznamům v .resx).
Pokud namísto .resx souborů chceme resources brát z jiného datového zdroje, např. databáze, je to jednoduché. ASP.NET pro tuto situaci používá provider-model a celá akce se v zásadě odehrává v následujících třech až čtyřech krocích:
- vytvoření vlastního resource-providera, tj. třídy implementující rozhraní IResourceProvider a zejména jeho metodu GetObject(),
- vytvoření ResourceProviderFactory třídy, na kterou se deleguje rozhodování ASP.NET o tom, kterého resource-providera má pro jednotlivé situace použít, v našem případě našeho resource-providera z bodu 1,
- nasměrování konfigurace ASP.NET na používání připravené ResourceProviderFactory třídy (úprava web.configu),
- pokud chceme zachovat, nebo alespoň simulovat generovaný namespace Resources, musíme ho buď také generovat (nepravděpodobné), nebo si od NET4 výše můžeme krásně vypomoci dynamickým objektem.
Pojďme se podívat na jednotlivé kroky podrobněji:
1. Vytvoření vlastního resource-providera
Resource-provider, je odpovědný za vlastní implementaci vyhodnocování resource-výrazu, tj. v něm ztvárním náš kód, který bude hodnoty resources číst z databáze, XML, nebo jiného zdroje, dle našeho uvážení.
Resource-provider je třída, která implementuje rozhraní IResourceProvider. To má zejména metodu object GetObject(string resourceKey, CultureInfo culture). Vstupem zde není resourceClass, který jak později uvidíme naopak dostává již ResourceProviderFactory a pro každou resourceClass je tak typicky vytvářena samostatná instance resource-providera odbavující danou resourceClass. IResourceProvider předepisuje ještě implementaci property IResourceReader ResourceReader, nicméně v běžných scénářích se bez implementaci readeru obejdete.
Primitivní implementace resource-providera pak může vypadat například takto:
namespace MyResourceProviders { /// <summary> /// Resource-provider pro lokální i globální resources z DB. /// </summary> public class MyResourceProvider: IResourceProvider { private string _classKey;
#region Constructors /// <summary> /// Initializes a new instance of the <see cref="XeroxWebToolResourceProvider"/> class. /// </summary> /// <param name="classKey">identifikátor resources třídy (cesta a název souboru pro lokální, název třídy pro globální)</param> public XeroxWebToolResourceProvider(string classKey) { _classKey = classKey; } #endregion
#region GetObject /// <summary> /// Returns a resource object for the key and culture. /// </summary> /// <param name="resourceKey">The key identifying a particular resource.</param> /// <param name="culture">The culture identifying a localized value for the resource.</param> /// <returns> /// An <see cref="T:System.Object"/> that contains the resource value for the <paramref name="resourceKey"/> and <paramref name="culture"/>. /// </returns> public object GetObject(string resourceKey, CultureInfo culture) { Debug.Assert(!String.IsNullOrEmpty(resourceKey)); // contract zajišťuje již interface
if (culture == null) { culture = CultureInfo.CurrentUICulture; }
return ResourceHelper.GetString(_classKey, resourceKey, culture); } #endregion
#region ResourceReader /// <summary> /// Gets an object to read resource values from a source. /// </summary> /// <value></value> /// <returns> /// The <see cref="T:System.Resources.IResourceReader"/> associated with the current resource provider. /// </returns> public IResourceReader ResourceReader { get { throw new NotImplementedException(); } } #endregion } }
Implementace třídy ResourceHelper, resp. její metody GetString(resourceClass, resourceKey, culture) již je samozřejmě na Vaší fantazii. Nemusíte samozřejmě tuto funkčnost ani vytahovat do samostatné třídy, ale můžete ji implementovat in-line.
3. Vytvoření ResourceProviderFactory
Abychom našeho připraveného resource-providera dostali do hry, musíme připravit ještě jednoduchou třídu odvozenou od předka ResourceProviderFactory, která jak už název napovídá bude odpovědná za volbu a vytváření instancí příslušných tříd resource-providerů. Teoreticky můžeme mít totiž pro různé množiny resources mít úplně jiné resource-providery, část nechat v .resx souborech, část mít v DB, atp. Rozhodujícím faktorem pro volbu resource-providera je zde informace o tom, jestli se jedná o globální nebo lokální resources a dále v případě globálních resourceClass a v případě lokálních virtualPath odkazujícího prvku.
ResourceProviderFacotry má dvě abstraktní metody, které musíme implementovat - CreateGlobalResourceProvider() a CreateLocalResourceProvider(). Primitivní implementace odkazující se na našeho resource-providera z předchozího kroku může vypadat třeba takto:
namespace Havit.XeroxWebTool.WebBase.ResourceProviders { /// <summary> /// Resource-factory vracející InformResourceProvider pro lokální i globální resources. /// </summary> public class MyResourceProviderFactory : ResourceProviderFactory { #region CreateGlobalResourceProvider /// <summary> /// When overridden in a derived class, creates a global resource provider. /// </summary> /// <param name="classKey">The name of the resource class.</param> /// <returns> /// An <see cref="T:System.Web.Compilation.IResourceProvider"/>. /// </returns> public override IResourceProvider CreateGlobalResourceProvider(string classKey) { return new MyResourceProvider(classKey); } #endregion
#region CreateLocalResourceProvider /// <summary> /// When overridden in a derived class, creates a local resource provider. /// </summary> /// <param name="virtualPath">The path to a resource file.</param> /// <returns> /// An <see cref="T:System.Web.Compilation.IResourceProvider"/>. /// </returns> public override IResourceProvider CreateLocalResourceProvider(string virtualPath) { string classKey = virtualPath; if (!string.IsNullOrEmpty(virtualPath)) { classKey = virtualPath.Remove(0, 1); // odstranění počátečního lomítka } return new MyResourceProvider(classKey);
} #endregion } }
3. Konfigurace použití ResourceProviderFactory (web.config)
Posledním nutným krokem ke zprovoznění vlastní logiky resources je sdělit ASP.NET prostřednictvím web.configu, že si přejem používat naší ResourceProviderFactory. Děje se tak prostřednictvím elementu globalization, atributu resourceProviderFatoryType:
<globalization ... resourceProviderFactoryType="MyResourceProviders.MyResourceProviderFactory, MyAssembly"/>
Element globalization patří do configuration/system.web/globalization, pokud je Vaše aplikace lokalizována, již ho tam pravděpodobně budete mít.
4. Náhrada za namespace Resources (volitelně)
Pokud přesouváte resources projektu do DB dodatečně, je možné, že v kódu již na mnoha místech používáte strong-type odkaz na prvky namespace Resources, kterou ASP.NET generuje ke globálním resources. V takovém případě se budete potřebovat s tímto kódem nějak vypořádat, protože nebudete-li používat .resx soubory, namespace Resources se Vám nebude generovat.
Jednou z možných cest, jak toto vyřešit, je použití dynamického objektu NET4.
V zásadě jde o to, že místo namespace Resources vytvoříte třídu odvozenou od předka DynamicObject a v příslušných předcích (PageBase, UserControlBase) vytvoříte dynamic property Resources. Ve zkratce může implementace třídy vypadat takto:
namespace MyResources { /// <summary> /// Pomocná třída pro přístup k Resources z kódu. /// </summary> public class Resources: DynamicObject { #region Constructors public Resources() : base() { } private Resources(string key):base() { this.ResourceClass = key; } #endregion
#region ResourceClass /// <summary> /// ResourceClass pro načítaný resource /// </summary> private string ResourceClass { get; set; } #endregion
#region TryGetMember (override) /// <summary> /// Vrátí požadovanou property /// </summary> /// <param name="binder"></param> /// <param name="result"></param> /// <returns></returns> public override bool TryGetMember(GetMemberBinder binder, out object result) { if (this.ResourceClass == null) { result = new Resources(binder.Name); } else { result = ResourceHelper.GetString(this.ResourceClass, binder.Name, Thread.CurrentThread.CurrentUICulture); } return true; } #endregion } }Ve třídě PageBase/UserControlBase potom zadefinujete property takto:
protected readonly dynamic Resources = new Resources();(Předka všech stránek/usercontrolů, pokud to zatím nepoužíváte, dostanete do hry z web.configu pomocí atributů pageBaseType a userControlBaseType na elementu configuration/system.web/pages. Budete se na něj však muset odkazovat i z code-behind tříd.)
Viz též
- Extending the ASP.NET 2.0 Resource-Provider Model [MSDN, Michèle Leroux Bustamante]
|
-
-
Symptom
Všechny requesty na WebResource.axd (včetně základních na .NET skripty) končí chybou 404 - "This is an invalid webresource request.", resp. "Toto je neplatný požadavek webového prostředku."
Cause
Problém byl v tom, že na serveru byl nastaven čas o několik měsíců nazpět.
Jestli tomu vadí, že aplikace byla kompilována později, než je datum/čas na serveru, nebo co konkrétně je problém, to jsem nehledal. Každopádně navrácení korektního data okamžitě problém vyřešilo.
|
-
V ASP.NET byla objevena (a zveřejněna!) bezpečnostní chyba, která sofistikovanějšímu útočníkovi umožní získat obsah zdrojových souborů uložených na webovém serveru, včetně web.configu. Podrobnosti popisuje ve svém blog-postu Scott Guthrie. Workaround spočívá v zapnutí customErrors bez rozlišování typu chyby.
Kdo by to chtěl vidět na vlastní oči, tak na YouTube je pěkné video.
|
-
Nedávno se mi připomněla jedna starší lahůdka (čti obskurnost, za kterou může ten zpropadený svět heterogenních browserů) - Device Filters. Dovolím si tedy připomenout:
Jde o víceméně elegantní deklaratorní zápis, jak nastavovat různé hodnoty jednotlivých properties controlů a direktiv v ASP.NET v závislosti na browseru. Syntaxe je jednoduchá:
<asp:Label IE:Text="Používáte Internet Explorer" Mozilla:Text="Používáte Firefox" PIE:Text="Používáte Pocket IE" Text="Používáte Buchvíco" runat="server" />Není to jen o properties controlů, dá se to použít i pro direktivy, takže například pro <%@ Page %> lze nastavit MasterPageFile či Theme. Rozpoznávané browsery se řídí browser-definition-files (App_Browsers, browserCaps).
|
-
Že Microsoft ASP.NET team si už delší dobu hraje s věcmi kolem CSS Sprites se vědělo už dlouho. Nakonec nečekají na další release ASP.NET a uvolnili svůj ASP.NET Sprite and Image Optimization Framework už nyní (na Codeplex). Pokud tedy chcete na svých webech optimalizovat rychlost načítání a zobrazování obrázků, určitě doporučuji Vaší pozornosti. Kdo netušíte, o co jde, potom viz instruktážní video (ve zkratce jde o slučování několika obrázků do jednoho a zobrazování výřezů z něj na Vaší webové stránce pomocí CSS stylování s background-image).
|
-
Měl jsem příležitost zúčastnit se beta programu nových certifikačních zkoušek Microsoftu pro platformu .NET 4, nedá mi to tedy, abych se s Vámi nepodělil o první dojmy (výstup je naštěstí již značně cenzurován, za ty dva dny už jsem trochu vychladl a nepublikovatelný proud mého hodnocení dopadl jen na prvních pár lidí, které jsem potkal).
První zkouška, kterou jsem testoval, byla zkouška na datové přístupy z kategorie Technical Specialist. Dle očekávání a zaměření se jednalo o "kodérskou" zkoušku, kde nešlo o nějaké koncepční myšlení, ale otázky směřovaly většinou na konkrétní code-snippety, nebo jiné coding techniky pro přístup k datům. V podstatě se vše točilo kolem následujících témat: - Entity Framework - odhadem 40%
- LINQ, LINQ to SQL - odhadem 20%
- pure DB Access (DbConnection, DbCommand, ...) - odhadem 10%
- "old fashion" (DataSet, DataTable, TableAdapter, ...) - odhadem 10%
- ostatní všechno možné (XML, ADO.NET Data Services, Sync Services, konfigurace, ...) - odhadem 20%
V zásadě se jedná o standardní zkoušku tohoto "kodérského" typu, kde se opět objevilo pro mě nepochopitelné množství otázek směřujících čistě na názvy/signatury jednotlivých metod. Něco, co v reálné praxi zcela řeší IntelliSense. Nesnáším otázky typu "Abyste udělali XY, použijete metodu: ExecuteQuery(), ExecuteQuery(true), ExecuteQuery(false) nebo ExecuteQuery<Order>()?". Naopak tam úplně chyběla sebemenší otázka na SqlTransactions, T-SQL, SQL-injection, apod., kteréžto znalosti bych od člověka certifikovaného na Data Access očekával (narozdíl o detailů o předávání Table Parameters nebo Spatial Data z kódu a podobných nuancí, které si každý snadno najde, když je potřebuje). Celkové zkoušku hodnotím jako standardního následovníka dosavadních MCP kodérských zkoušek, kde Microsoft/Prometric nedokázali překonat svůj stín a místo, aby se soustředili na skutečné ověření dovedností vývojáře potřebných v každodenní praxi, tak šlo opět o koncentraci na novinky a okrajová témata, které jsou zrovna "in". Člověk, který takovou zkoušku úspěšně absolvuje, není vůbec ověřen na základní koncepty přístupu k datům, spíše se dokázal připravit na požadavky zkoušky způsobem, který mu umožnil ji absolvovat (ať už pomocí zkušebních testů, uniklých otázek, nebo tvrdým biflováním faktů), nicméně stejně nelze úspěšně předpokládat, že by si běžný vývojář detaily, které jsou předmětem zkoušky zapamatoval déle než potřebný půlden.
Druhá zkouška, kterou jsem testoval, byla z kategorie Professional Developer pro Web Development. Zkouška by se měla zaměřovat na koncepty a znalost technologie, prakticky bez kódování. V hodnocení této zkoušky jsem bohužel mnohem radikálnější, točila se totiž celá kolem následujících témat: - MVC - odhadem 50%
- ASP.NET Core Infrastructure - odhadem 25%
- WebForms - odhadem 10%
- Ostatní (Data Access, WCF, Silverlight, jQuery, ...) - odhadem 15%
Totální zahlcení problematikou MVC mě velmi nemile překvapilo. Nikdy jsem neměl nic proti lidem, kteří se rozhodli věnovat této technologické masturbaci (dovoluji si vypůjčit trefné označení kolegy Michal Altaira Valáška), ale kdo v Microsoftu/Prometric došel k závěru, že pro testování dovedností samostatného webového vývojáře (dovedností relevantních pro běžnou praxi!), je nutné tak silně zdůraznit nové MVC a prakticky zcela opustit WebForms přístup, to mě hlava nebere. Toto mě znechutilo natolik (a tento feedback, že by se měly oddělit zkoušky na MVC a Webforms, jsem dával do Microsoftu už dávno v dobách, kdy ještě bylo co měnit), že odsuzuji tuto zkoušku jako absolutně irelevantní vzhledem k hodnocení reálného webového vývojáře. Pokud bych měl posuzovat jeho dispozice a dovednosti pro reálnou praxi vývoje webových aplikací, tato zkouška by mi toho mnoho neřekla. Bohužel i těch několik otázek, které by tématicky patřily do podobné zkoušky, bylo položených tak, že často vůbec nesměřovaly k jádru věci, ale jednalo se např. o vyloučení zcestných odpovědí, aby zůstaly ty méně špatné. Když se Vás někdo zeptá, které dva druhy ovoce byste doporučili někomu, kdo má rád sladkosti, tak Vám z nabídky "okurky", "igelit", "brambory" a "mramor", nezbývá než zaškrtnout... (ne, bohužel tlačítko WTF testovací aplikace nenabízí a co považují autoři za správnou odpověď se můžeme jenom dohadovat).
|
-
XmlDataSource má poměrně předurčený scénář použití a dokáže velmi nemile překvapit, pokud zapojíte vlastní fantazii a v dobré víře ho použijete jinak (ač zdravý člověk by očekával, že to fungovat bude). Tak především:
- vlastnost EnableCaching je defaultně nastavena na true (což není úplně očekávané, ale budiž, dokumentované),
- Cache je však poměrně zákeřná a ne vždy reflektuje vaše změny, vše se odvíjí od implementace metod GetXmlDocument() a CreateCacheKey(), z nichž lze vyčíst, co všechno považuje XmlDataSource za změnu situace vyžadující reload dat a co ne.
- tak například změna hodnoty property Data (zápis nového XML stringu) změnou pro Cache není a XmlDataSource vesele vrací stále původní XML až do vypršení Cache!
- za změnu se považuje zejména změna v hodnotě DataFile nebo TransformFile, dále pak změna souboru, na který se DataFile nebo TransformFile odkazují,
- XmlDataSource je tedy předurčeno pro použití právě přímo s XML soubory uloženými na disku, na které se odkazujete pomocí DataFile a TransformFile, zatímco přímé nastavování property Data je poněkud nedotažený scénář (i když přípustný).
...z čehož se pro mě jen potvrzuje, že datasources (CokolivDataSource) jsou cesta do pekel. :-)
|
-
Na Microsoft DevDays 2009 v Praze a Ostravě jsem mimo účasti na MVP stánku Ask the Experts prezentoval dvě dema svých nejoblíbenějších novinek v Dev10 platfromě. Jejich zdrojové soubory Vám nyní nabízím ke stažení:
Na webu www.devdays.cz jsou ke stažení prezentace, webcasty a screencasty k dalším přednáškám této akce.
|
-
V nastavení application poolu na IIS je zastrčeno jedno nastavení s výchozí hodnotou 1, které je poměrně zrádné, pokud ho někdo změní a neví, co to přesně znamená.
Jde o volbu "Maximum Worker Processes" a neznalé svádí tuto hodnotu z jedničky zvětšit na vyšší číslo.
Co to však ve skutečnosti znamená - jde o to, že IIS pustí pro Application Pool více instancí Worker Processu (w3wp.exe), které jsou navzájem izolované. Vznikne tak více nezávislých instancí aplikací běžících na daném Application Poolu a celé se to začne chovat jako Web Garden (= lokální virtuální Web Farm na jednom serveru). Následky jsou pak prakticky stejné, jako běh aplikace na webové famě - instance aplikace mezi sebou nezdílí kontext (Application, Cache, in-proc Session, atp.).
Protože každý Váš request pak může vyřdit jiná instance aplikace, projevy mohou být např. následující:
- ztrácí se Vám Session, pokud používáte výchozí InProc session (hodnoty Session jsou uloženy na jiném "serveru", než který vyřizuje aktuální request),
- nefunguje dobře cachování (každý "server" si udržuje vlastní cache a musí se tedy naplnit tolik cachí, kolik "serverů" Vám běží),
- ztrácí se Vám hodnoty Application contextu (opět stejný důvod),
- nefungují Vám grafy DevXpress (protože si obrázek ukládají do lokálního contextu v okamžiku renderování stránky s grafem a požadavek browseru na obrázek grafu se dostane na jiný "server"),
- atp. atp.
Osobně v běžném provozu nenacházím scénář, kde by Maximum Worker Processes mělo být nastaveno jinak než na 1. Dokážu si představit jedině, že někdo chce záměrně testovat chování své aplikace na webové farmě, nebo nějaké obskurní důvody s unmanaged componentami, nebo řešením nedostatečné thread-safety aplikace).
|
-
Pokud Vám po nastavení ASP.NET routingu na IIS7 v integrated-mode nechodí na stránkách Session, pak je potřeba elementu system.webServer/modules nastavit atribut runAllManagedModulesForAllRequests na true:
<system.webServer> <modules runAllManagedModulesForAllRequests="true"><!-- bez tohoto s ASP.NET Routingem nechodí Session v integrated-mode --> <remove name="UrlRoutingModule" /> <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </modules> ......ono to není jenom o Session, pro ASP.NET Routing se v integrated-mode nespouští moduly, které mají pre-condition managedHandler.
|
|
|
|