XML adatkötés a gyakorlatban

Korábban már írtam arról, hogy az MSDN Kompetencia Központ RSS feedjét a FeedBurner szolgáltatás segítségével mérjük. A FeedBurner biztosít egy webes felületet a statisztikai adatok lekérdezéséhez, de ezen kívül egy REST-es API-t is ad, ami lehetővé teszi, hogy közvetlenül saját alkalmazásunkban jelenítsük meg ezeket az adatokat.

Az Awareness API legegyszerűbb metódusának meghívásához egy HTTP GET kérést kell küldenünk a szervernek az alábbi formában:

http://api.feedburner.com/awareness/1.0/GetFeedData?uri=myfeeduri

A válasz pedig az alábbi szerkezetű XML:

<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok">
    <!-- This information is part of the FeedBurner Awareness API. 
         If you want to hide this information, you may do so via your FeedBurner Account. -->
    <feed id="1352372" uri="myfeeduri">
        <entry date="2008-06-01" circulation="27" hits="161" />
    </feed>
</rsp>

A lényeg természetesen a date, circulation és hits attribútumokban van, a feladat ezeknek a megjelenítése. Egyedül arra kell odafigyelnünk, hogy a válasz csak abban az esetben érvényes, ha a stat attribútum értéke ok. Ellenkező esetben kissé eltérő a válasz felépítése és a hibaüzenetet egy err elem msg attribútumában kapjuk meg.

LINQ to XML

Miután van már LINQ XML-hez is, csábító, hogy ezzel oldjuk meg a feladatot. Ehhez mindössze ennyi kódot kell írnunk:

    XDocument doc = XDocument.Load( url );
    string status = doc.Root.Attribute( "stat" ).Value;

    if( status.Equals( "ok", StringComparison.OrdinalIgnoreCase ) )
    {
        XElement entry = doc.Descendants( "entry" ).First();
        string date = entry.Attribute( "date" ).Value;
        string circulation = entry.Attribute( "circulation" ).Value;
        string hits = entry.Attribute( "hits" ).Value;

        // TODO: Megjelenítés vezérlőkben...
    }
    else
    {
        string error = doc.Descendants( "err" ).First().Attribute( "msg" ).Value;

        // TODO: hibaüzenet megjelenítése
    }

Ez persze jól működik, de mégis elgondolkodtam azon, hogy mindezt meg lehet-e oldani deklaratív módon, C# kód nélkül?

XML adatkötés

A jó hír az, hogy pontosan erre szolgál az XML adatkötés, ami már ASP.NET 2.0 óta elérhető, csak éppen szeretünk megfeledkezni róla. Ha mégis eszünkbe jut, akkor hajlamosak vagyunk hierarchikus adatszerkezetekkel társítani és csak hierarchikus vezérlőkben, menü vagy fa kontrollokban gondolkodni. Pedig az XML adatkötés tökéletesen működik GridView vagy az új ListView vezérlőkkel is.

Először szükségünk lesz egy XmlDataSource vezérlőre:

    <asp:XmlDataSource ID="xdsFeedService" runat="server" 
        XPath="//rsp/feed/entry" 
        DataFile="http://api.feedburner.com/awareness/1.0/GetFeedData?uri=myfeeduri" />

A DataFile paraméterben akár HTTP-s URL-t is megadhatunk, az XPath attribútum pedig arra szolgál, hogy a válasz XML-ból kiemeljünk egy részt egy XPath kifejezés segítségével, jelen esetben az entry tag-et.

A megjelenítéshez egy ListView vezérlőt használhatunk, ezzel ugyanis pontosan kézben tartható a generált HTML kód. Például így:

    <asp:ListView runat="server" DataSourceID="xdsFeedService">
      <LayoutTemplate>
        <asp:PlaceHolder runat="server" ID="itemPlaceholder" />
      </LayoutTemplate>
        
      <ItemTemplate>
        <asp:PlaceHolder runat="server" 
          Visible='<%# XPath("//rsp/@stat").ToString().Equals( "ok", StringComparison.OrdinalIgnoreCase ) %>'>                
          Date: <asp:Literal runat="server" Text='<%# XPath("@date") %>' />
          <br />
          Circulation: <asp:Literal runat="server" Text='<%# XPath("@circulation") %>' />
          <br />
          Hits: <asp:Literal runat="server" Text='<%# XPath("@hits") %>' />                        
        </asp:PlaceHolder>
                
        <asp:PlaceHolder runat="server" 
          Visible='<%# !XPath("//rsp/@stat").ToString().Equals( "ok", StringComparison.OrdinalIgnoreCase ) %>'>
          Error: <asp:Literal runat="server" Text='<%# XPath("//rsp/err/@msg") %>' />
        </asp:PlaceHolder>
      </ItemTemplate>
    </asp:ListView>

Néhány érdekesség a fenti kódból:

  1. A ListView vezérlőnek szüksége van egy itemPlaceholder azonosítójú vezérlőre az oldalon, amit én egy LayoutTemplate megadásával oldottam meg.
  2. Az XML adatkötéshez nem az Eval, hanem az XPath metódust kell használnunk, aminek egy XPath kifejezést kell megadnunk. Mivel az XmlDataSource-ban már leszűkítettük a válasz XML-t, most olyan XPath kifejezéseket kellett írnom, amelyek ebben a leszűkített kontextusban értelmezhetőek. A @hits például az aktuális entry elem hits attribútumára vonatkozik, míg a //rsp/err/@msg megadásával gyökér relatív útvonalat adtam meg.
  3. Az ItemTemplate-et kettébontottam két Placeholder segítségével, és amennyiben a válasz helyes az elsőt jelenítem meg, amennyiben pedig hibaüzenetet kapunk vissza, a második Placeholdert használom. Az elrejtéshez szintén XML adatkötést használtam, a Visible tulajdonságban szereplő kifejezés a stat attribútum értékét vizsgálja.
  4. Minden esetben a legegyszerűbb vezérlőt használtam, nem Labelt és Panelt, hanem Literalt és Placeholdert. Ezek nem generálnak extra kódot a kimenetbe, de támogatják az adatkötést.

Érdemes megfigyelni, hogy ez a megoldás teljesen deklaratív, nem igényel C# kódot.

Felmerülhet a kérdés, hogy akkor most melyik a jobb? Én általában jobban szeretem a deklaratív megoldást, mert számomra általában áttekinthetőbb és így a kód karbantarthatóbb. Webalkalmazásról lévén szó, természetesen a teljesítmény is fontos szempont, marad tehát a mérés, mérés, mérés.

 

Advertisements

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s