június, 2007 havi archívum

Ez egy tutorialhoz tartozó leírás! A turtorial erről a címről érhető el:

 
A cikksorozat záró részeként az SqlCacheDependency-t vesszük górcső alá. Ez az objektum szerintem a legérdekesebb a három közül, hiszen imperatívan és deklaratívan is használhatjuk, illetve az egyszerűsége miatt több helyen is megbújva várja, hogy előcsalogassuk.
Erről található a legtöbb leírás, így ezek átolvasása után egy eléggé részletes képet kaptam a témáról, melyet kiegészítve a saját tapasztalataimmal megszületett ez a cikk. 
    
SqlCacheDependency, minek kell még egy?
Jogosan merül fel bennünk a kérdés, hogy tényleg szükségünk van erre? A választ nem lehet csak úgy egyből rávágni, hogy igen vagy nem.
Sok helyen csak az SqlDependency-t említik érthető módon, hiszen az ASP.NET mellett winforms, console alkalmazásokból is elérhető.
Az SqlCacheDependency-t igazából inkább csak kényelmesebb használni, de nem kapunk semmi olyat, amit eddig ne tudtunk volna megoldani SqlDependency-vel.
Hatékonyság szempontjából viszont állítólag az SqlCacheDependency valamivel alatta marad az SqlDependency-nek.
Tehát amint láthatjuk összetett kérdésről van szó. Ez olyan, mint a memória vs. műveletigény. A cikk olvasása során ezeket tartsuk szem előtt.
 
Honnan származik ?
Mint ahogy már említettem, eléggé széleskörű támogatás van ASP.NET-ben SqlCacheDependency ügyileg. Ez annak is köszönhető, hogy a Notification és ASP.NET Cache között jött létre a kapcsolat. Így a CacheDependency osztály egy alosztályaként az SqlCacheDepenency magába zárja (encapsulate) az SqlDependency-t, úgy, hogy közben megtartja a CacheDependency-s viselkedését. Ennek a származtatásnak köszönhető az, hogy a másik két objektummal ellentétben nem a System.Data.SqlClient névtéren belül található, hanem a System.Web.Caching névtér alá került.
Az SqlCacheDependency-t két helyről is tudjuk használni. Van értelemszerűen a kódból történő elérés, illetve van egy rövidebb út, amikor magából az oldalról érjük el (deklaratívan).
 
Kódból történő használata
Imperatív használatra egy példa
Ahhoz, hogy kódból tudjuk használni az SqlCacheDependency-t két dologra van szükségünk. Első az, hogy az SqlDependency.Start() tagfüggvényével feliratkozunk a lekérdezés figyelésre, ugyanúgy, mint ahogy az előző cikkben is tettük.
A második dolog, amire szükségünk van, hogy létre kell hoznunk egy példányt az SqlCacheDependency-ből. Majd a megfelelő beállítások elvégzése után a Response.AddCacheDependency() tagfüggvénnyel hozzáadjuk a cache függőséget alkalmazásunkhoz. Nézzük meg egy példaalkalmazás keretén belül, hogy is történik mindez.
 string connstring = "Data Source=.\\SQLEXPRESS;DataBase=AdventureWorks;Integrated Security=True; Asynchronous Processing=true";
   using (SqlConnection conn = new SqlConnection(connstring))
   {
     string query = "SELECT ProductId AS Azon, Name AS Név, ProductNumber, Color FROM Production.Product Where Color Like ‘%Black%’";
     using (SqlCommand comm = new SqlCommand(query, conn))
     {
        try
        {
            conn.Open();
            SqlCacheDependency dependency = new SqlCacheDependency(comm);
            int expire = 3;
            DateTime exp = DateTime.Now.AddMinutes(expire);
            Response.Cache.SetCacheability(HttpCacheability.Public);
            Response.Cache.SetExpires(exp);
            Response.Cache.SetValidUntilExpires(true);
            Response.AddCacheDependency(dependency);
            GridView1.DataSource = comm.ExecuteReader();
            GridView1.DataBind();
        }
        catch (SqlException exp)
        {
            Response.Write(exp.Message);
        }
        finally
        {
            conn.Close();
        } //finally
     } //using command
   } //using connection
A SetCacheAbility()-ig a kód szerintem teljesen egyértelmű, hogy mit csinál az alkalmazás. Az előbb említett tagfüggvény egy HttpCacheAbility enumerátort vár, amely arra való, hogy beállítsuk vele a HTTP fejléc Cache-Control értékét. Ezzel azt szabjuk meg, hogy hol gyorsítótárazható az adat (szerver által küldött válasz). Például a Private (alapértelmezett) esetén csak a kliensnél (proxy nem tárolja); Public esetében pedig proxy-nál is és kliensnél is, illetve, ha csak a szerveren szeretnénk tárolni, akkor a Server-t válasszuk az enumerátornál.
A SetExpires() értelemszerűen az elévülési időt szabja meg, a SetValidUntilExpires() pedig azt, hogy az ASP.NET mellőzi-e a klienstől érkező érvénytelenítési kérelmet. A tapasztalat az, hogy vele is meg nélküle is tökéletesen működik az alkalmazás!
 
Cache API-s gyorsítótárazás I.
Még kétfajta lehetőséget villantanék meg, hogy hogyan lehet a Cache-hez hozzáadni ilyen  függőséget. Cache API-t használja mindkettő (ezeket nem tartalmazza a példaalkalmazás!).
Az első egy egyszerű függőséget szab meg, egy általunk megadott objektumhoz. Ez az objektum általában vagy egy DataSet vagy egy DataTable.
DataTable cache_table = new DataTable();
SqlDataReader datareader = comm.ExecuteReader();
cache_table.Load(datareader);
Cache.Insert("Products", cache_table, dependency);
 
Cache API-s gyorsítótárazás II.
A másik lehetőség ennél egy kicsit többet nyújt számunkra. Konkrétan a változásról való értesítéshez rendelhetünk egy delegate-t, így megtudhatjuk a cache érvénytelenítés okát. Ehhez szükségünk lesz egy CacheItemRemoveCallBack objektumra, mely segítségével a delegate-ünket össze tudjuk kapcsolni a gyorsítótárazott object-tel.
Cache.Insert("Products", cache_table, dependency, DateTime.Now.AddMinutes(3), TimeSpan.Zero, CacheItemPriority.Default, new CacheItemRemovedCallback(CacheChanged));
 
private static void CacheChanged(string key, object cacheitem, CacheItemRemoveReason reason)
{
   AddToLog("Az alábbi kulcsú cacheitem törölve lett a cacheből! Kulcs: " + key + ", ok: " + reason.ToString());
}
Az Insert ezen túlterhelésének a következő a szintakszisa:
Cache.Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpriration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
A key a kulcs, amely alapján a későbbiek tudunk rá hivatkozni.
A value a gyorsítótárazandó objektum.
A dependencies a cache függőség, ami lehet akár fájl is.
Az absoluteExpiration az elévülési idő. Ha abszolút lejárati időt adunk meg, akkor a slidingExpiration vagy Cache.NoSlindingExpiration vagy TimeSpan.Zero legyen!
A slindingExpiration az utolsó hozzáféréstől számított elévülési idő. Ha ennél csúszó Expiration-t adunk meg, akkor az absoluteExpiration paraméternek feltétlenül Cache.NoAbsoluteExpriration-nak kell lennie!
Az onRemoveCallback segítségével iratkozunk fel arra az eseményre, ami akkor hajtódik végre, ha a cache tartalma érvénytelenítve illetve törölve lett.
Az érvénytelenítés oka (tehát a CacheItemRemoveReason enumerátor) a következők valamelyike lehet: Expired | Removed | Underused | DependencyChanged re-create item and add back to cache as required.
Természetesen az Insert párjával az Add-del is tökéletesen működik mindkét példakód!
 
Page Fragment Cache, avagy az OutputCache direktíva
Lekérdezés alapú cachelés
Deklaratív módon kétféleképpen is lehet használni a QN-t. Az egyik esetben egy lekérdezésre szabhatunk meg változásfigyelést, míg a másik esetben egész adattáblákra! Kezdjük először a lekérdezéses verzióval. Ilyenkor igazából, csak a kódunkon rövidítünk. A következő pár sor helyett összesen egy sort kell majd beírnunk az aspx fájlba:
 SqlCacheDependency dependency = new SqlCacheDependency(comm);
 int expire = 3;
 DateTime exp = DateTime.Now.AddMinutes(expire);
 Response.Cache.SetCacheability(HttpCacheability.Public);
 Response.Cache.SetExpires(exp);
 Response.Cache.SetValidUntilExpires(true);
 Response.AddCacheDependency(dependency);
Az OutputCache direktívát kell szerkesztenünk. Itt meg kell adnunk a Duration-t, amivel az elévülési időt szabjuk meg, illetve a VaryByParam-ot, mely az itt felsorolt paraméterek minden egyes változatához létrehoz egy cachelt verziót az oldalból. Például ha van olyan paraméterünk, hogy Countries, akkor lesz egy Hun verziós oldal cacheitem-ünk, illetve mondjuk egy Eng is. Eddig még semmi újdonság nincs ASP.NET 1.X-hez képest. De 2.0-ban már van egy SqlDependency attribútum is. Ennek értékül most adjuk azt, hogy CommandNotification!
<%@ OutputCache Duration="3600" VaryByParam="*" SqlDependency= "CommandNotification" %>
Így futtatva az alkalmazásunkat, ugyanazt az eredményt kapjuk, mint amikor imperatívan adtuk a cache-hez az SqlCacheDependency-t.
 
Tábla alapú cachelés
Ehhez a verzióhoz semmilyen mögöttes kódra nincs szükségünk, csak a web.config-ra és az aspx fájlra. Web.Config-ban azt állítjuk be, melyik adatbázist szeretnénk úgy cachelni, hogy változás esetén a cache tartalma érvénytelenítődjön. Ehhez először a connectionstrings részlegben vegyünk fel egy adatkapcsolati sztringet:
<connectionStrings>
  <clear/>
  <add name="localhost" connectionstring="Data Source=.\SQLEXPRESS; DataBase=AdventureWorks; Integrated Security=True" providerName="System.Data.SqlClient">
</connectionStrings>
Majd a cache szekción belül az sqlcachedependency alszekcióban létre kell hozni egy adatbázisra való hivatkozást (ez system.web-en belül van a connectionStrings-sel ellentétben):
<caching>
 <sqlCacheDependency enabled="true">
  <databases>
   <add name="AW" connectionStringName="localhost" pollTime="60000" />
  </databases>
 </sqlCacheDependency>
</caching>
Két dologra hívnám fel a figyelmet. Az egyik az, hogy a pollTime-ot (milliszekundum) nem kötelező megadni SQL Server 2005 esetén, ellentétben az SQL Server 2000-rel. 2000 esetén másképp történik a változásfigyelés, konkrétan nem triggerekkel, hanem pollingolással. A másik dolog pedig az, hogy mint minden web.config-beli szekcióhoz, ehhez is létezik egy osztály, mely segítségével egyes dolgokat képesek vagyunk manipulálni kódból. Ez az SqlCacheDependencySection osztály. Tulajdonságain keresztül el tudjuk érni a <databases> keretein belül megadott adatbázisokat, kikapcsolhatjuk a cachelést, átállíthatjuk a polltime-ot, stb. Sajnos viszont, mint ahogy az összes többi szekciót kezelő osztály, ez sem képes új dolgok felvételére, pedig szerintem hasznos lehetne, ha kódból is felvehetnénk adatbázisokat. Ez van, ezt kell szeretni.
Ezek után dobjunk az oldalra egy SqlDataSource-t, illetve egy GridView-t. (A korábbiakban használt lekérdezést használom a példaalkalmazásban). Miután megvagyunk mindenféle adatkötéssel, jöjjön a dolog érdemi része, a cachelés beállítása:
<%@ OutputCache Duration="3600" VaryByParam="None" SqlDependency= "AW:Production.Product" %>
Az SqlDependency-nél a szintaktika a következő: dependency_name:table_name.  A dependency_name a web.config-ban megadott adatbázis referencianév, a table_name pedig értelemszerűen az adatbázis egy táblája. Arra is van lehetőségünk, hogy egyszerre több táblát figyeltessünk, például, ha master-details táblákat jelenítünk meg egy GridView-ban. Ilyenkor egymástól pontosvesszővel válasszuk el a két tábla referenciát, pl.: sqldependency="northwind:products; northwind:categories"
 
SqlCacheDependencyAdmin
Az ASP.NET 2.0 tartalmaz egy olyan objektumot, amellyel a kódunkból is tudjuk kezelni az adatbázisra/adattáblákra vonatkozó változásfigyelést. Néhány fontos metódusát emelném csak ki:
EnableNotifications, engedélyezi a connectionstringben kapott adatbázisnál a változásfigyelést
EnableTableForNotification, adatbázis egy adott táblájához engedélyezi a change notification-t. Második paraméterként kell megadni a táblanevét (első paraméter szintén a connstring)
DisableNotification, DisableTableForNotifiction letiltják a változásfigyelést
GetTablesEnabledForNotifications, visszaad egy string típusú tömböt, melyben azok a táblanevek lesznek benne, melyeknél engedélyezve van
Fontos még azt megjegyezni szerintem, hogy ha nem tudunk az adatbázishoz csatlakozni, akkor ez az objektum egy HttpException-t dob, nem pedig egy SqlException-t! Illetve pl.: a GetTablesEnabledForNotifications metódusnál akár még DatabaseNotEnabledForNotificationException is kaphatunk, ha nincs engedélyezve a QN!
 
FONTOS: Ha sémával rendelkező táblánál szeretnénk engedélyezni a QN-t,, akkor sajnos egy kicsit módosítunk kell egy tárolt eljárást. Ha nem tesszük meg, ilyesmi hibával fogunk találkozni:
Cannot create trigger ‘Owner.TableName_AspNet_SqlCacheNotification_Trigger ‘ as its schema is different from the schema of the target table or view. Failed during cache dependency registration.
Please make sure the database name and the table name are valid. Table names must conform to the format of regular identifiers in SQL.
Ezt a bugot úgy tudjuk kiküszöbölni, ha a példaalkalmazás mappájában lévő New_Aspnet_SqlCacheRegisterTableStoredProcedure.sql-t futtatjuk az adott adatbázisnál!
 
Egyéb adatobjektumok gyorsítótárazása
DataSources – Cache
Az új ADO.NET 2.0 vezérlők, azon belül az adatforrás vezérlők (DataSource controls) mindegyike képes valamilyen szintű adat cachelésre (csak SqlDataSource-os kódot tartalmazza a példaalkalmazás!). Egyetlen dolgot igényel mindegyik, mégpedig azt, hogy a DataSourceMode DataSet legyen (ez az alapértelmezett is). A kívánságuk érthető, hiszen DataReader esetén nem készítünk másolatot az adatbázisról, ha mégis ezt próbálnánk meg használni, egy NotSupportedException-t fogunk kapni.
Alapjában véve, csak egyféleképpen lehet mindegyikben a gyorsítótárazást kikényszeríteni, kivéve az SqlDataSource-nál(2) illetve SiteMapDataSource-nál(0).
Az alábbi 4 tulajdonság segítségével finoman hangolhatjuk a cachelést:
EnabledCache: gyorsítótárazás engedélyezése
CacheDuration: elévülési idő (másodpercben kell megadni, a változatosság kedvéért)
CacheExpirationPolicy: A CacheDuration-re tudjuk megszabni, hogy Abszolút (Absolute) vagy Csúszó (Sliding) idő legyen. Amint már erről fentebb is volt szó, az abszolút: a gyorsítótárba való elhelyezéstől számított Duration idő után évül el, míg a csúszó az utolsó hozzáféréstől számítva méri ugyanezt az időt!
CacheDependencyKey: függőségi feltétel, bár ez kicsit eltér az eddig megszokottaktól. Ez a kulcs hivatkozik az összes olyan objektumra, melyet a datasource control hozott létre cacheléskor. Amint megváltozik a kulcs értéke, akkor a cache tartalma érvénytelenítődik. Kódból a legegyszerűbb érvényteleníteni.Nézzünk egy példát:
<asp:AccessDataSource ID="ProductsDSource" runat="server"
    DataFile="~/App_Data/Northwind.mdb"
    SelectCommand="SELECT * FROM [Products]"
    CacheDuration="30"
    EnableCaching="True"
    CacheKeyDependency="ProdDepKey">
</asp:AccessDataSource>

void Page_Load(object sender, EventArgs e)
{
  if (IsPostBack)
    Cache[ProductsDSource.CacheKeyDependency] = someData;
}

void OnItemUpdated(object sender, DetailsViewUpdatedEventArgs e)
{
  Cache.Remove(ProductsDSource.CacheKeyDependency);
  GridView1.DataBind();
}
Miért is van erre szükség? Azért, mivel se az Object, se az XML, se az Access nem tartalmaz QN-t, így nekünk kell kézzel érvénytelenítenünk (legegyszerűbb megoldás: remove). De továbbra is szinkronba (konzisztensen) tartjuk a „kinézetet”, és ismét cacheljük az adatokat. Természetesen nem csak Update esetén kell ezt végrehajtatni, hanem Insert-nél, Delete-nél is!
 
SqlDataSource +1 cache
Az SqlDataSource kitüntetett a DataSource-ok között, mivel az SQL Server támogatja a QN-t. Így bekerült a tulajdonságai közé egy SqlDependency is. (VS05 Beta1 illetve Beta2 esetén még az AccessDataSource-nál is volt ilyen tulajdonság, bár NotSupportedException-t dobott, de szerencsére a véglegesbe már nem került bele).
Ez az SqlDependency viszont teljesen ugyanúgy működik, mint ahogy az QutputCache-nél (dependency_name:table_name). Lássuk a medvét:
<asp:SqlDataSource Id="SqlDSource" runat="server"
   ConnectionString= "<%$ConnectionStrings:localhost%>"
   SelectCommand="SELECT ProductId AS Azon, Name AS Név, ProductNumber, Color FROM Production.Product Where Color Like ‘%Black%’"
   DataSourceMode="DataSet"
   EnableCaching="True"
   CacheDuration="60"
   CacheExpirationPolicy="Sliding"
   SqlCacheDependency="AW:Production.Product">
</asp:SqlDataSource>
Ezt pedig már csak meg be kell állítani egy GridView DataSourceId-jának. Ennyi az egész, és ugyanazt csinálja, mint az eddigi kódok. Egy megjegyzés: ez egy leheletnyivel lassabb, mint az QutputCache, de cserébe egyszerűbb használni (properties ablak!).
 
Konklúzió
Amint azt a cikkben láthattuk az SqlDependency és Cache együttműködésének köszönhetően, adataink gyorsítótárazása és emellett konzisztenciájuk megőrzése többé nem jelent problémát.
Végszóként, összességében a Query Notification egy nagyon hasznos dolog tud lenni, ha gyorsítani szeretnénk az alkalmazásunkat, és jobb teljesítményt akarunk elérni!
A hőség riadó miatt illetve vizsgaidőszak miatt ezen a héten szünetel a blog szolgáltatás!
 
Jővő héten hétfőn lesz az utolsó vizsgám, ami analízis, így eléggé sok időm elmegy ennek elsajátításával. Így sajnos a Query Notification befejező cikkje is csúszik. Megértéseteket és elnézéseteket kérem!
 
Illetve sajnos nem tudok ott lenni Platform Innovációs napon, de ha valaki ír róla élmény beszámolót, akkor azt kiteszem a blogba, természetesen szerző nevével együtt!!!!
 
Akiknek ilyen space-s tárhelye azok tudják, hogy van egy statisztika oldal, ahol megtudják nézni hányan, mikor ás honnan jutottak el az oldalra és mit néztek meg. (az elmúlt 24óra adatait menti csak a rendszer!)
Először is köszönöm azt a 2000 látogatást amit produkáltatok a blog indulása óta.
A második dolog pedig az, hogy ahogy nézegettem kik milyen keresési feltételekkel jutottak el kereső oldalakról, néhány érdekes dolgot tapasztalatam.
 
A két leggyakrabban keresett szöveg a következő két kifejezés volt (vagy ezek valamely permutációja):
Mi a .NET Framework 2.0
Mi az a DOTNET
 
Ebből azt a messze menő következtetést sikerült levonnom, hogy akik most szeretnének belekóstolni a DOTNET csodálatos világába, azoknak nincs egy konkrét hely, ahol elkezdhetnénk, vagy csak nem ismerik a devportalt… Nem tudom erre megoldást fog-e adni a Zsolték által elindítani kívánt VS Klubok, melyekbe remélem kezdők is egyaránt csatlakozhatnak a szakértők mellé.
 
A másik, amit a previous page-kből sikerült megtudnom, hogy nem csak magyar oldalakról keverednek ide. Például már háromszor is jöttek orosz oldalról is ide, illetve ma reggel egy brazil kereső oldalról is:
 
Vizsgaidőszak után igyekszem pótolni a lemaradásom! Kellemes hetet mindenki, és igyatok sok folyadékot, ne hogy hőbutát kapjatok vagy kiszáradjatok!
 

 
szerk. 21:13
Mai nap is volt alkotás
 
Ismét egy e-mail, de most nem verseny, hanem rendezvény.  Az e-mail tartalmát szószerint nem idézném, inkább csak a lényegét:
 
Időpont: 07.06.25
Helyszín: BME
 
Témák:
– A Windows Vista innovatív, a fejlesztőket érintő újdonságai
– A .NET keretrendszer áttekintése és új kiegészítései
– A Visual Studio következő változatának szolgáltatásai
– Új látványtechnológiák, felhasználói élményrendszerek
– Együttműködés a fejleszt"ok és a vizuális szakemberek között
A rendezvény programja
 
8.30 – 9.00
 Regisztráció
 
9.00 – 10.30
 Windows Vista rendszer szintű innovációk
–  hálózatkezelés
–  fájlrendszer
–  kommunikáció
–  grafikus alrendszer
 
10.30 – 10.50
 Kávészünet
 
10.50 – 12.20
 .NET 3.0 fundamentumok
–  CLR, Base Class Library
–  Foundation-ök (.NET 3.0)
–  Adatkezelés (.NET 3.5)
 
12.20 – 13.00
 Ebédszünet
 
13.00 – 14.30
 A prezentációs alaptechnológiák spektruma
–  Széles körben elérhető új alkalmazások (Web 2.0)
–  Következő generációs grafikus képességek (Windows)
–  Fejlesztő/Tervező eszköz támogatás
 
14.30 –
 Regionális Visual Studio fejlesztői klub elindítása

Előadok:
Bátorfi Zsolt
Novák István

Regisztráció:
http://www.microsoft.com/hun/platformnapok


A nap poénja így a bejegyzés végére:
http://www.google.hu/search?hl=hu&q=world+of+warcraft+sql+server&btnG=Google+keres%C3%A9s&meta
World of Warcraft server keresésnél a gugli ezt az oldalt dobja ki másodiknak

 

Euro Skills Verseny 07

Posted: 2007. június 14. in Rendezvény információk
A napokban kaptam erről a versenyről egy e-mailt, így gondoltam megosztom veletek még időben
 
Az e-mail szövege:

Verseny 2007
A Microsoft és a Cisco közös versenye
 
 
Kedves középiskolás diákok, főiskolai  és egyetemi hallgatók, fiatal szakemberek!
 
2007 szeptemberétől több száz csapat, több mint fél éven keresztül küzd majd az értékes díjakért és azért a dicsőségért, hogy ők képviselhessék Magyarországot 2008-ban, a rotterdami EuroSkills 2008 szakmai csapatverseny döntőjében, az Office Team Challange kategóriában.
 
Ez a Verseny más lesz, mint a többi!  Igazi kihívás és kaland!
 
Tervezd meg, rendezd be és működtesd a 21. század behálózott világának legkorszerűbb munkahelyét. Vezesd az irodát, szervezd a munkát,  és  legyél te, aki az informatikai hálózatot működteti.
 
Ne várj szeptemberig, már most keresd meg a csapatodba a megfelelő szakembereket! 
 – Az ideális csapat négy 16 és 23 év közötti diákból vagy fiatal szakemberből áll.
 – A tagok között van két számítógépes guru, akik  a hálózati eszközökkel is kiválóan bánnak, és két fő akik  képesek  a legkorszerűbb informatikai környezetben működő kisvállalkozás irodáját irányítani, a mindennapi teendőket szervezni, az IKT-s eszközöket hatékonyan használni
 – Mindenki érti és beszéli az angol nyelvet, kreatív, és képes a valódi csapatmunkára
 
Jelentkezési határidő: 2007. szeptember 21.
 
További információk, regisztráció és feliratkozás hírlevélre: www.microsoft.hu/verseny2007
 … 

 

Chapter X. Instrumentation Second Part (rendszer felügyelet 2. rész)
 
A 10. fejezetet tárgyaló blog bejegyzések közül az elsőben megmutattam, hogy ki-mikor ír az eseménynaplóba illetve mi szükséges ahhoz, hogy mi magunk is tudjunk oda menteni.
Ma egy konkrét példaalkalmazást mutatnék ennek a használtára illetve utána haladók majd tovább a fejezet többi részére is.
A példaalkalmazásunk egy valós életből vett problémára alapszik. Mi történjen akkor, hogy a felhasználó egy nem létező oldalra navigál el? Ilyenkor értelemszerűen nem szeretnénk, ha a kliens a sárga hibaüzenet ablakkal találkozna, ezért átirányítjuk egy custom error page-re, illetve jelzünk az adminisztrátornak is, hogy valami gebasz volt.
Először készítsük el az átirányítást. Ehhez a web.config fájlban a customerror szekciót kell beállítanunk a system.web részen belül. Íme a kód, majd utána a magyarázat:
<customErrors mode="RemoteOnly" defaultRedirect="error_page.aspx">
        <error statusCode="404" redirect="page_not_found.html"/>
        <error statusCode="503" redirect="service_unavailabled.html"/>
</customErrors>
 
A mode = RemoteOnly segítségével azt állítottuk be, hogy az ASP.NET hiba oldal, csak lokális felhasználóknak jelenjen meg. Távoli kérés esetén először az ASP.NET megnézi, hogy beállítottunk-e egyedi hiba oldalt, és ha nem akkor egy IIS errort fog megjeleníteni.
A mode-t még két értékre állíthatjuk be On-ra illetve Off-ra. Off (ez az alapértelmezet) esetén a helyi illetve távoli gépeken is a default hiba oldalt jeleníti meg. Az On módban pedig az egyedi hiba oldalt jeleníti meg, ha beállítottuk. Ha nem hoztunk létre ilyet, akkor az default error page leírja, hogyan állítsuk át remote módba a szolgáltatást, és utána már kaphatunk információt a hiba eredetéről.
A defaultRedirect attribútum arra szolgál, hogy hova irányítsa át az oldalt alapértelmezetten, ha bármilyen hiba történik, beleértve a lekezeletlen hibákat (unhandled exception), http hibákat (http errors), stb.
Az alatta lévő részt, vagyis az error gyerek elemeket (elements) opcionálisan lehet megadni. Itt az egyes http hibakódokhoz tudunk rendelni a statusCode segítségével egyedi oldalt a különböző error-ok esetén. Például érdemes külön választani a server hibákat (500 felett) a többitől.
 
Most nézzük meg azt, hogy hogyan tudunk az adminunknak(vagy esetlegesen magunknak) üzenni hiba esetén. Kétféle helyen tudunk ugyebár hibát kezelni, oldal illetve alkalmazás szinten. Oldal szinten eléggé egyértelmű hogyan kell, ezért nézzük alkalmazás szinten (application-level). Ilyenkor értelemszerűen a global.asax fájlban kell keresgélünk, és rövid kereső hadjáratunk után rátalálunk az Application_Error eseményre. Csattogjuk be a következő kódot, majd utána egy rövid magyarázat:
 
string ErrorDescription = Server.GetLastError().Message.ToString();
string EventLogSource = "WebApps_Errors";
if (!EventLog.SourceExists(EventLogSource))
{
  EventLog.CreateEventSource(EventLogSource, EventLogSource);
}
Eventlog Log = New EventLog();
Log.Source = EventLogName;
Log.WriteEntry(ErrorDescription, EventLogEntryType.Error);
Az EventLog forrás nem más, mint az eseménynapló bal oldalán lévő bejegyezés gyűjtemények valamelyike. Pl.: Alkalmazás, Rendszer, stb..  Mi szeretnénk, ha lenne egy külön ilyen, ahol a webalkalmazásaink hibát gyűjtené össze. A CreateEventSource tagfüggvény paraméterei elsőre kicsit megtévesztők: source, logname. A racionális gondolkodással ellentétben itt a source nem az EventLogSource, tehát nem a gyűjteményneve, és a logname sem a bejegyzés nevét szabja meg. Hanem éppen ellenkezőleg! A logname-nél kell megadni, hogy az Application, System vagy saját gyűjteménybe akarjuk a napló bejegyzést írni. A source-nál pedig azt állítjuk be, hogy melyik alkalmazás váltotta ki, tehát mi legyen a neve.
Példaalkalmazás lévén, most nálunk mind a kettő megegyezik!
 
Ezek után, ha a gyanútlan felhasználó elnavigál egy nem létező oldalra, akkor a page_not_found.html oldalra irányítjuk át(ezt azért hozzuk létre:D), és egy Error bejegyzés is keletkezik az eseménynaplóban WebApps_Errors néven. A bejegyzés leírásában (description) láthatjuk, hogy ilyenkor például HttpException volt.
 
Folytatva tovább a 10. fejezetet ismét olyan dologba botlunk, ami másként van webapp-nál, mint winforms-nál, ez a trace. A Debug teljesen hasonlóan működik, ugyanúgy tudunk írni az Output ablakba illetve egy messagebox-szerűségbe. A trace mint ahogy már arról szó volt vagy az oldal aljához csapódik hozzá, vagy pedig egy külön trace.axd fájlt hoz létre a nyomon követéshez. Egy megjegyezendő dolog: az IsEnabled egy eléggé hasznos és gyakran használt tulajdonsága a Trace osztálynak!
Akinek ehhez esetleg szükségese lenne tutorialra:
http://msdn2.microsoft.com/en-us/library/y13fw6we(VS.71).aspx
(oldalnál a trace engedélyezése, trace bejegyezés írása, alkalmazás szintű engedélyezés, trace információ olvasás)
 
Ehhez a fejezethez még egy aprócska példakódot fűznék már csak hozzá, ami arra szolgál, hogy az ASP.NET (worker) process-ről adjon infókat. Ehhez a ProcessModelInfo osztályt használjuk:
 
ProcessInfo AspNetInfo = ProcessModelInfo.GetCurrentProcessInfo();
 
lblProcID.Text = AspNetInfo.ProcessID; 
lblStartTime.Text = AspNetInfo.StartTime; 
lblRunningTime.Text = AspNetInfo.Age.Days + " nap, " + AspNetInfo.Age.Hours + ":" + AspNetInfo.Age.Minutes; 
lblReqCount.Text = AspNetInfo.RequestCount;
lblProcStat.Text = AspNetInfo.Status;
lblPeakMem.Text = AspNetInfo.PeakMemoryUsed;
 
Először az azonosítót kérjük le, majd azt, hogy mikor indult a process, utána pedig hogy mióta fut. Végül a beérkező kérések számát, a státuszt ,illetve a max memóriafogyasztást tudjuk meg.
Van még egy érdekes tagfüggvénye a ProcessModelInfo-nak, ez a GetHistory(), ami egy int paramétert vár. Ez a szám azt szabja meg, hogy a legutóbbi hány infót kérjük le. Ezt akár adatforrásnak is megadhatjuk, például egy gridview-nak.
A blog bejegyzés igaz történet alapján készült!
 
A szöveg írása alatt senki se sérült meg, vagy vesztette életét!
 
A példakódokon profi kaszkadőrök dolgoztak, kérjük ne próbálják ki otthon!

Egy nem mindennapi blog bejegyzés!

Posted: 2007. június 12. in Egyéb
Ez a bejegyezés kicsit más lesz, mint az eddigiek (de csak ma!). Lesz szó Surface-ről, kockulásról és lesz egy jó pár videó! Csapjunk is bele.
Microsoft nem régiben pontosabban (05.29) rántotta le az asztalterítőt a Surface névre keresztelt dohányzó asztaláról. Mielőtt mindenki gyorsan bezárni ezt az ablakot és megfogadná, hogy ide se jövők többet, az előtt vessen egy pillantást az alábbi képekre

illetve az előd:

Különvélemény

Hát nem szép? 10 000 dolláros dohányzó asztal, amire ha véletlen ráhamuzunk felismeri a cigi márkáját és megmondja, hogy hány százalékban károsodott már a tüdőnk. Na azért itt még nem tartunk, de nézzük mit is rejt magában ez a csöpnyi szerszámos láda.
Nincs bill, egér csak toachscreen, érintőképernyő van, ami a maga 30 hüvelykével nem is olyan rossz. DLP projektoros megoldással vetítik a képernyőt az üvegre. Több infrakamera is pásztázza egyszerre a felületet, így egy időben nem csak egy ujj kezelheti az alkalmazást, hanem akár több tucat, egymástól függetlenül!
Az egyik igazi különlegessége, hogy sok mobil eszközt is bevonhatunk a munkakörnyezetünkbe, amelyek közötti kommunikáció végtelen leegyszerűsödik. Mind összesen annyira van szükségünk, hogy valamilyen vezeték nélküli technológiát támogasson az adott eszköz, amelyet ráhelyezünk a kijelzőre, pl.: Bluetooth, WiFi.
Mint mindennek az MS-nél ennek is volt egy másik neve, ami jelenleg már csak kódneve (lásd. longhorn >> vista), ez a Milan. Egy kis kitérőt kell tennem, mert sajnos nem tudom megállni, hogy ne írjak ezekről a kódnév (codename) mániáról és átnevezgetésről, ami most az MS-nél van. Szal sorban nevezik át a jobbnál-jobb nevekre elkeresztelt termékeit semmit mondó bugyuta nevekre. pl.:
Windows Lognhorn Server >> Windows Server 2008;
Visual Studio Orcas >> Visual Studio 2008;
Sql Server Katmai >> Sql Server 2008
Íme egy HIVATALOS ms videó, erről az elnevezéses koncepcióról:
http://ikszkom.freeblog.hu/archives/2007/05/29/Windows_Server_2008_nevadas/
Visszatérve még annyit akarok mondani a Surface-s videót előtt, hogy ezt a technológiát már viszonylag régebb óta fejlesztgették, pontosabban 2001-ben vágtak bele. Több videó is megjelent időközben róla (pl.: amint éppen world of warcraft-oznak rajta, vagy amerikát pásztázzák 3d-ben), illetve más gyártók is elkezdték a sajátjaikat kifejleszteni.
Szal íme egy videó, ami bemutatja, hogy mire is jó a surface illetve, hogy mi lapul a képernyő mögött (Behind the Screen):
 http://www.popularmechanics.com/technology/industry/4217348.html
 
Egy érdekesség még, hogy a surface hivatalos oldalán csak egy fekete háttér jön be. Hát igen, fő a titokzatosság:D  Valójában csak annyi történt, hogy a megszokottnál jóval többet kell várni arra, hogy a bufferelést jelező ízléstelen rózsaszín (javítsatok ki, ha rossz rgb színt írtam) karika megjelenjen. Utána a másik nagy csalódás, hogy silverlight helyett flashben készítették el az oldalt.
 
 
 
 
Akiknek még nem esett le az álluk ettől, azoknak egy kis segítség, hogy leessenek a székről a röhögéstől!
 
10 jel ami arra utal, hogy kocka vagy (mármint hexaéder):
 
0. feleségem megkérdezi, hogy "Hol van a …….., nem láttad?" És mivel nem
láttam, az első értelmes válasz ami az eszembe jut: "guglizz rá".
 
1. az hétköznapok csipcsup ügyei kapcsán is az jut eszedbe: "huhh, ebből
de jó blogbejegyzést lehetne írni este!"
 
10. mikor a barátaim túlnyomó többségétől életszerűbb úgy elköszönni, hogy
"viszlát, este skype?", mintsem hogy azt mondani majd telefonálok vagy
valami hasonló..
 
11. hogy egyes ismerőseimnek csak a netes nickneve jut most eszembe
 
100. IRL is odaírtam egy papírra a feleségemnek hogy LOL és szegénynek
fogalma sem volt róla, hogy mit is jelent
 
101. a fiammal olyat játszottunk, hogy mond egy szót és én rávágok egy
megfelel"o párt (pl. hideg-fagyi,mese-shrek,leopárd-párduc,vár-katona
stb.) és szegény csak nézett, mikor a denevérre mint a villám rávágtam
hogy "thebat", majd egy pillanattal később hozzátettem: "vagy Batman!"
 
110. az esetek túlnyomó többségében már valami netes szolgáltatást
használok jegyzettömbként, hogy ne felejtsek el semmit
 
111. vacsora közben a kék tálcát bámulva először az jut eszembe, hogy vajon
mi lehet a színkódja majd kicsit később az, hogy ezt melyik grafikához
lehetne felhasználni mert tetszik
 
1000. reggel először nyomom be a gépet, majd csak utána teszem fel a kávét
főzni. Bár hozzáteszem, ezt nagyon logikusan meg tudom magyarázni. 🙂
 
1001. az erkélyről kibambulva a szembe parkoló autó szélvédőjén észreveszem,
hogy milyen eszméletlen szép az égen egy felhő rajzolata, majd erről
beugrik hogy milyen jó HDR képeket láttam múltkor ilyen témában a
fotozz.hu-n és bejövök a szobába hogy megkeressem a HDR képek
készítéséről szóló cikket majd gépelés közben beugrik, hogy jobb lett
volna inkább feltekinteni és megnézni azt a felhőt élőben is.
És végül egy .NET Framework paródia videó! Aki megmondja, hogy miért HL-es cd-t tart a srác a kezében, az kap tőlem egy…(még kitalálom, hogy mit):
 
Mai egy rendhagyó blog bejegyzést sikerült úgy érzem kreálnom, amiben az újdonság és komolytalanság jól megfért egymás mellett. Remélem elnyerte tetszéseket, így ha lesz rá igény, máskor is esetleg összedobok valami hasonló kockulás mentesítő koktélt!
 

Chapter X. Instrumentation (rendszer felügyelet)
 
Sajnos igazán jó magyar címet nem tudtam adni ennek a fejezetnek, mivel az Instrumentation szó azt jelenti, hogy műszerezés, hangszerelés. A fejezetben pedig rendszer diagnosztikáról van szó (ez látszik is a használt névtérből: System.Diagnostics), ezért döntöttem inkább a rendszer felügyelet mellett.
Webalkalmazás esetén Event Log-ba való mentés kétfajtaképpen történhet: általunk illetve ASP.NET által. Az általunk készíthető eseménybejegyzések mentése az eseménynaplóba, eléggé jól le vannak írva a könyvben. De, ez csak windows alatt igaz! Ugyanis ASP.NET esetén, mint ahogy már megszokhattuk kicsit másképp van. Alapértelmezés szerint nem tudunk bejegyzést írni az EventLog-ba, mivel az ASPNET usernek nincs hozzá jogosultsága, így Registry-ben kell neki jogot adni.
Adjunk neki!:
– Először indítsuk el a regedit-et, majd keressük meg a HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\ részt.
– Itt válasszuk az Edit menüből a Permission-t (szerkesztés|engedélyek)
– Kattintsunk az Add gombra és vegyük fel az ASPNET user-t! Emlékezzünk vissza win2k3 estén már Network Service (NTService) user nevében futnak az ASP.NET folyamatok.
– Klikk az Ok gombra, majd adjunk fullcontol jogot neki!
– Mindent okézzunk le, majd ilyenkor érdemes újra indítani az ISS-t (iisreset).
Ha ezt nem tesszük meg, akkor egy System.Security.Exception-t fogunk kapni.
 
Lehetőségünk van arra is, hogy ne a usernek adjuk jogot, hanem az alkalmazásunknak. Ilyenkor két módszer is a rendelkezésünkre áll.
1 módszer:
Navigáljunk el regedit-ben a HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application alkulcshoz.
Itt jobb klikk az Application kulcson, majd add >> key
Pötyögjük be az alkalmazás nevét, végül zárjuk be és öröm ujjongjunk.
 
Másik módszer, hogy az EventLogInstaller-t használjuk.
Hozzunk létre egy saját osztályt, majd adjuk hozzá a System.Configuration.Install.dll-t referenciát. Így egy csomó dolgot megsporolhatunk például ezt:
[RunInstaller(true)]
public class EventLogSource: Installer
 
Hozzunk létre egy példányt az ELI-ből:
EventLogInstaller eventsourceinstall = new EventLogInstaller();
 
Állítsuk be a eseményforrást:
eventsourceinstall.Source = ”Sample_Application”;
 
Majd adjuk át az egészet az Installernek:
Installers.Add(eventsourceinstall);
 
Fordítsuk le, majd végül futtassuk:
InstallUtil EventLogSource.dll
 
Azt, hogy létezik-e az adott eseményforrás pedig az EventLog.SourceExists() függvényével tudjuk leellenörizni.
Az ASP.NET is automatikusan logolja  például a lekezeletlen kivételeket (unhandled exception), illetve rendszer hibákat is. Tipikus lekezeletlen hiba például, ha az url-ben tárolt querystringet nem ellenőrizzük le, mivel ilyenkor a rosszindulatú felhasználó simán átírhatja a neki tetsző értékre az általunk beállított kulcsok értékét. Ilyenkor csak Waring-ot, sárgalapot kapunk. Kivételesen egész értelmesen le van írva, ilyenkor a hiba oka, amit utána így egyszerűen orvosolhatunk. Rendszer hiba esetén már nem ilyen kedves velünk az asp.net, ott már piroslap-ot, error-t kapunk. Nálam ami például többször is előjött ilyen hiba, hogy egy mappán belül nem lehetséges két különböző asp.net verziójú alkalmazás futtatása. De nem csak az ASP.NET-től kaphatunk automatikusan ilyen figyelmeztetéseket, hanem a .NET Runtime-tól is!
Tehát az ASP.NET inkább csak akkor logol ha valamiféle baj van, ellentétben például az SQL Server-rel. Ő szereti tudatni a rendszergazdával, vagy adott esetben a felhasználóval (ha alkalmazásból olvassuk fel a log bejegyzéseket), hogy él és virul. Az automatikus alkalmazás bejegyzések ~90%-át teszi általában ki.
 
Elméletben arra is van lehetőségünk, hogy egy EventLog objektum Entries gyűjteményét átadjuk adatforrásként valamilyen adatmegjelenítő vezérlőnek, amely támogatja az ICollection interfészt.
 
folytatjuk…
A Július 22-től 27-ig megrendezésre kerülő Zánkai Gyermek Üdülőbeli egyetemisáknak szóló turnus jelentkezési határidejét meghosszabították! (C típusú turnusra is lehet még regelni középiskolásoknak, turnus: júl. 29aug. 3
Így június elseje helyett e hét péntekig, aza jun. 8-ig lehet még regisztrálni!
 
Regisztrálni az alábbi címen lehet:
http://www.microsoft.com/hun/itvakacio/
 
 

Query Notification Bug Fix

Posted: 2007. június 6. in Bugs...
Amikor ADO.NET 2.0 segítségével egy alkalmazásunk feliratkozik a lekérdés értesítésre (QN), akkor sajnos nem minden alkalommal érkezik is üzenet.
A Microsoft elismerte, hogy ez egy bug miatt van, ezért kiadott egy patchet az SQL szerverhez.
A hiba akkor jelentkezik, amikor a feliratkozástól számított 5 perc letelik.
 
Így már müködni fog az SqlDependency-nél megadható timeout is! A konstuktora túlterhelt, ezért a 3 paramétert váró verziót használjuk. pl.:
SqlDependency depend = new SqlDependency(command,null,Int32.MaxValue);

A második paraméter azért null, mivel így a default service-t fogja használni! A timeout-nak megadott idő, pedig nem egy hamar fog letelni:D
 
Külön köszönet a linkért Alsecz Gábornak!
 
Patch letölthető innen:
Ez egy tutorialhoz tartozó leírás! A turtorial erről a címről érhető el:
 
Ebben a tutorialban az SqlDependency használatával fogunk megismerkedni. Mint ahogy az előző cikkben is említettem, ez az objektum reprezentálja az ADO.NET 2.0-ban a Query Notification magas szintű (high-level) kezelését. Az alacsony szintű (low-level) kezelést pedig a már kivesézett SqlNotificationRequest szolgáltatta.
 
SqlNotificationRequest vs. SqlDependency
Az igazi eltérés a két objektum között az, hogy használunk-e diszpécsert a kliens és az adatbázisszerver között az értesítések fogadására. Alacsony szintnél, nekünk kellett mindezt megoldani (multithread, waitfor, …). SqlDependency-nél viszont ez már alapban rendelkezésünkre is áll, csak el kell indítani a figyelést, illetve egyszer majd le kell állítani. Érdemes mindezt webalkalmazás esetén a global.asax fájlban az Application_Start illetve Application_End eseményeknél kezelni. WinForms-nál illetve ConsonleApp-nál pedig például az Inticialization()-ben meghívni a Start és Stop tagfüggvényeket.
Nézzük, hogyan is tehetjük meg mindezt:
Global.asax
void Application_Start
{
  bool started = System.Data.SqlClient.SqlDependency.Start(connstring, "ValtozasSor");
}
void Application_End
{
  System.Data.SqlClient.SqlDependency.Stop(connstring, "ValtozasSor");
}
 
Fontos megjegyezni azt, hogy a Stop illetve a Start tagfüggvények 2fajta paraméterezést fogadnak el, tehát túlterheltek (overload). Alapesetben csak egy ConnectionStringet várnak, és így is tökéletesen működnek. Viszont lehetséges az is, hogy egyszerre több kapcsolaton keresztül is kommunikálni szeretnénk a szerverrel. Ilyenkor érdemes a kétparaméteres túlterhelést használni és megadni azt, hogy melyik várakozási sort (queue) kezelje.
Ezekre a függvény hívásokra azért van szükségünk, mivel valójában a SqlDependency belsejében is egy SqlNotificationRequest dolgozgat.
 
Alkalmazás szerkezete nagy vonalakban
– lekérdezés összeállítása, command használata
– egy sqldependency objektum példányosítása,
— command-dal való összekapcsolása
– feliratkozás az OnChange eseményre
– lekérdezés végrehajtása
— cache-ben adateltárolása
– változás lekezelése
— cache-ben lévő adatok frissítése
 
Az SqlNotificationEventArgs
Az OnChange esemény, akkor hívódik meg, amikor a szervertől érkezik egy értesítés, hogy változás történt. Mint ahogy az előző cikkben is említettem, nem kapunk arról semmilyen információt, hogy mi változott meg illetve hol, csak annyit, hogy megváltozott. Szerencsénkre az OnChange eseménynél ennél kicsit többet is megtudhatunk a változást kiváltó okokról.
Ez az SqlNotificationEventArgs-nak köszönhető, amely a második paramétere az SqlDependency.OnChange eseményéhez rendelt eseménykezelőnek. Három fontos tulajdonsága van, amelyet lekérdezhetünk az Info, Source illetve a Type.
Az Info tulajdonságon keresztül arról kaphatunk információt milyen utasítás miatt történt változás (pl.: Update, Delete, stb.) Az értékét egy 18 lehetséges értéket tartalmazó enumerátortól kapja, amely nem más, mint az SqlNotificationInfo. Nem sorolnám fel mindegyiket, hogy mi mit is jelent, akit érdekel, az itt utána tud nézni neki:
http://msdn2.microsoft.com/en-us/library/system.data.sqlclient.sqlnotificationinfo.aspx
A Source tulajdonság azt határozza meg, hogy honnan lett meghívva a változást előidéző kifejezés. Ez lehet például client (pl.: timeout miatt), data (adatváltozás miatt(pl:insert)), database (adatbázis állapotváltozás (pl.:detached)), stb. A Source az SqlNotificationSource enumerátorból meríti a lehetséges értékeit (11).
A Type meglepő módon az SqlNotificationType enum-ra támaszkodik (3érték), és ennek segítségével arról kapunk infót, hogy egyáltalán sikerült-e feliratkozni a változás figyelésre. Ha Change, akkor minden okés, ha Subscribe, akkor van baj. Ilyenkor nézzük meg, mit kaptunk az Info-nál. Az Unknow pedig a legtökéletesebb lehetőség, amikor ő se tudja, hogy mi van.
 
Példaalkalmazás elkészítése
Kinézet

A webformra húzzunk egy Labelt, egy Gridview-t, illetve egy Button-t.
A Label-t nevezzük át lbl_notification-re, és töröljük a Text tulajdonságát. Állítsuk be a Font-nál a Size-t XX-Large-ra, hogy jól látható legyen mikor mi történt.
A Gridview-nak adjunk valamilyen pofás megjelenést, például Proffesional.
A Button-nak a text-jét írjuk át Frissítés-re. Kódot nem fogunk írni a Click eseményéhez, mivel a gomb célja összesen annyi, hogy újrageneráltassuk az oldalt (PostBack).
 
Kódok
Először implementáljuk a System.Data.SqlClient névteret. Az adatlekérést illetve az adatmegjelenését külön függvényben írjuk meg, hogy változás esetén könnyen tudjuk frissíteni a letárolt adatokat. Tehát lesz egy GetData és ShowData metódusunk. Hívjuk meg őket az oldal betöltésekor:
Page_Load
{
  GetData();
  ShowData();
}
 
Ezek után írjuk meg az adatlekérés kódját. Csak akkor kérünk le a szervertől adatokat, ha első oldalkérés történt, vagy változás. Ilyenkor az IsPostBack false értéket ad. Az első eset nem szorul magyarázatra, de a másik már inkább. Változás esetén azért nem történik PostBack, mivel az SqlDependency folyamatosan figyel, így ha változás történik, akkor az OnChange esemény hívódik meg és csak az ott kezelt kódok fognak végre hajtódni. Tehát ha a User Interface-el (UI) kapcsolatos kódot írunk, akkor nem fog érvényre jutni, mivel nincs új oldalgenerálás (render folyamat), mivel nem történt PostBack.
Az egyszerűség kedvéért a példában azokat a terméket kérjük le, amelyeknek a színe fekete. Ebből összesen 100db van az AdventureWorks adatbázis Production.Products táblájában. Íme a GetData függvény:
 string connstring = "Data Source=.\\SQLEXPRESS; DataBase=AdventureWorks; Integrated Security=True; Asynchronous Processing=true";
 SqlConnection conn = new SqlConnection(connstring);
 string query = "SELECT ProductId AS Azon, Name AS Nev, ProductNumber AS Termekszam, Color AS Szin FROM Production.Product Where Color Like ‘%Black%’";
  using (SqlCommand comm = new SqlCommand(query, conn))
  {
    try
    {
       SqlDependency depend = new SqlDependency(comm);
       depend.OnChange += new OnChangeEventHandler(OnChange);
       conn.Open();
       if (!IsPostBack)
       {
          DataTable dt = new DataTable();
          SqlDataReader reader = comm.ExecuteReader();
          dt.Load(reader);
          Cache["Products"] = dt;
       }//if
    }//try
    catch (SqlException exp)
    {
       Response.Write("Hiba történt! Infó: " + exp.Message.ToString());
    }
    finally
    {
       conn.Close();
    }//finally
  }//using
 
DataReader segítségével a DataTable Load tagfüggvényén keresztül töltjük fel az adattáblánkat, amelyet eltárolunk utána a Cache-ben.
Most írjuk meg az SqlDependency OnChange eseményt lekezelő kódot. Ez, ahogy az előző kódból is látszik, egy OnChangeEventHandler segítségével történik.
private void OnChange(object sender, SqlNotificationEventArgs e)
 {
    GetData();
    Cache["changes"] = "<b>Adat megváltozott, Cache frissítve!</b><br>" + e.Source.ToString() + e.Info.ToString() + e.Type.ToString();
 }
 
Meghívjuk a GetData() metódust, hogy frissítsük a Cache tartalmát (nem történt PostBack, tehát belépünk az if-be), majd pedig eltároljuk szintén a Cache-ben a változásról kapott információkat.
 
Végül már csak meg kell jelenítünk az adatokat a ShowData metódus segítségével.
private void ShowData()
 {
    if (Cache["changes"] != String.Empty)
    {
       lbl_notification.Text = (string)Cache["changes"];
       Cache["changes"] = String.Empty;
    }
    else
    {
       lbl_notification.Text = "Nem történt adatváltozás, Cache nem frissült!<br>";
    }
    DataTable dtable = (DataTable)Cache["Products"];
    GridView1.DataSource = dtable;
    GridView1.DataBind();
 }
 
Fontos, hogy ne felejtsük el castolni, mert a Cache-ben objektumokként van minden eltárolva!
Az alkalmazásunk úgy fog működni, hogy első oldalkéréskor végrehajtódik a GetData metódus, eltároljuk az adattáblát Cache-be, majd a ShowData segítségével megjelenítjük. Ezután, ha nem történik változás, akkor nem nyúlunk az adatbázishoz, hanem a Cache-ből szedjük az adatokat.
Ha változás történik, akkor frissítjük a Cache-t. Ebből a felhasználó nem fog látni semmit, csak majd a következő oldalkérésnél (tehát ha rákattint a gombra) a gyorsítótárban eltárolt már frissített adatokat jelenítjük meg, illetve felhívjuk a figyelmét arra, hogy az adatbázis módosult.
 
Profiler használata
Egy nagyon hasznos segédprogram az SQL Server Profiler, amely segítségével jobban meg tudjuk érteni a Query Notification működését. Ezen alkalmazás segítségével nyomon tudjuk követni, milyen utasításokat küldött a kliens az adatbázisszervernek illetve miket hajtott végre a server a tudtunk nélkül.
Például megtudhatjuk azt, hogy az SqlDependency.Start() függvény meghívásakor két utasítás is végrehajtódik az SQL szerver irányába. Az egyik egy lekérdezés, ami megnézi, hogy engedélyezve van-e a Service Broker szolgáltatás az adott adatbázisnál. A másik utasítás egy tárolt eljárást hoz létre, mellyel később majd a várakozási sort fogjuk üríteni, illetve a szolgáltatást.
Egyszer mindenféleképpen ajánlom, hogy nézzük meg milyen utasítások röpködnek az éterben a kliens és a db szerver között. Például sokszor fogunk az sp_executesql tárolt eljárással találkozni.
A legegyszerűbb módja a folyamat megértésének, ha néhány helyre töréspontokat helyezünk el: Tegyünk egy-egy BreakPoint-ot az Application_Start-hoz, az if(!IsPostBack)-hez illetve az OnChange-hez. Futtassuk az alkalmazásunkat (debug módban) és figyeljük közben a Profiler által rögzített T-SQL utasításokat.
 
Helyes lekérdezések
Sajnos nem minden típusú lekérdezésnél lehet használni a QN-t. Alábbi kritériumokat kell szem előtt tartanunk lekérdezéseink összeállításánál.
 
Mi Hány Merre?
– Az olyan tranzakcióról, T-SQL utasításokról, melyek egyszerre több változást is eszközölnek az adatbázisban, csak EGY értesítést küld a szerver a kliensnek!
– Ha végrehajtó kifejezést használunk, akkor az SQL szerver a végrehajtott parancsot regisztrálja be, mintsem magát az EXECUTE utasítást!
– Olyan parancsnál, amely több SELECT utasítást is tartalmaz, az SQL Server Engine mindegyik statement-et külön regisztrálja!
 
Lekérdezésben nem használható kifejezések
– * illetve [table_name].* oszlop lekérések
– névtelen illetve duplikált mezőnevek
– matematikai függvények csak a GROUP BY kulcsszóval együtt használhatóak!!
– HAVING, CUBE, ROLLUP
– PIVOT  vagy UNPIVOT operátorok
– INTERSECT vagy EXPECT operátorok
– Nézetre (view) való hivatkozás
– DISCINT, COMPUTE, COMPUTE BY, INTO
– globális szerver változók (@@változó_neve)
– származtatott, ideiglenes tábla hivatkozások, illetve tábla változók
– más adatbázis (esetleg szerver) tábláira, nézeteire hivatkozások
– al-lekérdezések, JOIN utasítások (mind külső, mind belső hivatkozások)
– nagy objektum típusok: text, ntext, image
– CONTAINS vagy FREETEXT teljes szöveges állítások
– rowset függvények, beleértve az OPENROWSET illetve OPENQUERY-t is
– összesítő függvények közül: AVG, COUNT(*), MAX, MIN, STDEV, STDEVP, VAR, illetve VARP
– nem determinisztikus függvények, beleértve a ranking és windowing függvényeket
– egyéni összesítések (user-definied aggregates)
– rendszer táblák, nézetekre való hivatkozások
– FOR BROWSE információk
– sorra (queue) való hivatkozások
– stb…
 
Bővebb információ az SQL Server Books Online –ban található Creating a Query for Notification címszó alatt található.