ASP.NET AJAX 4: Kliens oldali adatkötés – webszolgáltatáshoz

A cikksorozat előző részében bemutattam, hogyan használhatjuk az ASP.NET AJAX 4 kliens oldali DataView vezérlőjét helyi változókban tárolt adatok adatkötéssel történő megjelenítéséhez. Ebben a részben kiszakadunk a böngészőből és egy webszolgáltatástól kérjük le az adatokat.

A webszolgáltatás elkészítése

A feladat ugyanaz, mint az előző cikkben, országok listáját akarjuk megjeleníteni, ezért készítettem egy Country osztályt, amiben semmi logika nincs, csak összefogja a Name és Capital tulajdonságokat. Mivel ASMX webszolgáltatásból akarom használni, ezért fontos, hogy legyen neki paraméter nélküli konstruktora.

Ezek után készítettem egy CountryWebService.asmx nevű fájlt, benne a CountryService osztállyal. Fontos, hogy mivel AJAX-ból akarjuk meghívni ezt a webszolgáltatást, ezért nem csak a WebSerice, hanem a ScriptService attribútumot is rá kell ragasztanunk.

A webszolgáltatás osztályban készítettem egy privát List<Country> típusú mezőt, ami az adatbázisunkat reprezentálja, ezen fognak futni a kliens lekérdezések.

Eddig tehát semmi extra, itt tartunk:

  [WebService( Namespace = "http://balassy.spaces.live.com/Samples/" )]
  [WebServiceBinding( ConformsTo = WsiProfiles.BasicProfile1_1 )]
  [System.Web.Script.Services.ScriptService]
  public class CountryWebService : System.Web.Services.WebService
  {
    private List<Country> countries;

    public CountryWebService()
    {
        this.countries = new List<Country>()
        {
            new Country( "Austria", "Vienna" ),
            new Country( "Australia", "Canberra" ),
            // És még jó sok további Country...

        };
    }
  }

A WebMethodot úgy írtam meg, hogy paraméterként megkaphassa, hogy az országok neve vagy fővárosa szerint, illetve növekvő vagy csökkenő sorrendben kívánja a kliens megkapni az adatokat:

  [WebMethod]
  public Country[] GetCountries( string orderby, bool asc )
  {
    Func<Country, string> keySelector;        

    switch( orderby )
    {
        case "Name":
            keySelector = new Func<Country, string>( c => c.Name );
            break;
        case "Capital":
            keySelector = new Func<Country, string>( c => c.Capital );
            break;
        default:
            keySelector = new Func<Country, string>( c => c.Name );
            break;
    }

    IEnumerable<Country> result = asc ? 
this.countries.OrderBy( keySelector ) :
this.countries.OrderByDescending( keySelector ); return result.ToArray(); }

Ugyanez WCF-ben

Ha ugyanezt a webszolgáltatást nem ASMX-ben, hanem WCF-ben akarjuk elkészíteni, akkor kicsit többet kell dolgoznunk vele. Ugyanúgy szükségünk lesz egy CountryService osztályra és benne egy GetCountries metódusra, amiket szokás szerint meg kell jelölnünk a ServiceContract és OperationContract attribútumokkal. Továbbá mivel a szolgáltatás Country példányokat ad vissza, arra kellenek a DataContract és DataMember attribútumok.

Mivel a WCF szolgáltatásunkat AJAX-ból akarjuk meghívni, még nem vagyunk készen. Először is kell a szolgáltatás osztályunkra az AspNetCompatibilityRequirements attribútum:

  [AspNetCompatibilityRequirements( 
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed )]

Továbbá – mint minden WCF szolgáltatáshoz, ehhez is – feltétlenül szükség van egy gigantikus méretű, alig átlátható konfigurációs XML-re a web.config fájlba:

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <behaviors>
        <endpointBehaviors>
            <behavior name="CountryServiceAspNetAjaxBehavior">
                <enableWebScript />
            </behavior>
        </endpointBehaviors>
        <serviceBehaviors>
            <behavior name="CountryServiceBehavior">
                <serviceMetadata httpGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <services>
        <service behaviorConfiguration="CountryServiceBehavior" name="CountryService">
            <endpoint address="" binding="webHttpBinding" 
contract="CountryService"
behaviorConfiguration="CountryServiceAspNetAjaxBehavior" /> </service> </services> </system.serviceModel>

A sok beállítás közül a két legfontosabb a webHttpBinding és az enableWebScript.

Ha eddig készen vagyunk, akkor a kliensnek már mindegy, hogy milyen technológia dolgozik szerver oldalon.

Kliens oldali adatkötés deklaratívan

Az adatkötéshez kliens oldalon megint csak egy egyszerű HTML fájlt készítettem, benne script blokkokkal pedig betöltöttem az ASP.NET AJAX 4 JavaScript fájljait az ajax.microsoft.com CDN-ről. Az országok felsorolását most is ul-li listában végezzük el a kliens oldali DataView vezérlő segítségével, ami deklaratívan mindössze ennyi:

  <ul
      class="sys-template"
      sys:attach="dv"
      dv:autofetch="true"
      dv:dataprovider="Services/CountryWebService.asmx"
      dv:fetchoperation="GetCountries"
      dv:fetchparameters="{{ { orderby: 'Name', asc: true } }}" >
      <li>
          {{ Name }} ({{ Capital }}) 
      </li>
  </ul>

dv:dataprovider

A DataView dataProvider tulajdonságával adjuk meg, hogy honnan jönnek az adatok. Ez lehet egy sima JSONos webszolgáltatás URI, egy Sys.Net.WebServiceProxy példány vagy bármilyen osztály, ami implementálja a Sys.Data.IDataProvider interfészt, azaz van fetchData metódusa. Az utóbbira példa a Sys.Data.AdoNetServiceProxy osztály, amivel ADO.NET Data Services (Astoria) szolgáltatásokat hívhatunk meg, a legegyszerűbb esetben pedig közvetlenül rámutathatunk az .asmx vagy az .svc fájlra.

dv:fetchoperation

A DataView a fetchOperation tulajdonságban várja annak a metódusnak a nevét, amit a webszolgáltatáson meg akarunk hívni. Ide lehet query stringet is írni, ami ADO.NET Data Services (Astoria) esetén további lehetőségeket ad szűrésre, rendezésre, lapozásra.

dv:fetchparameters

A fetchParameters tulajdonságon keresztül paraméterezhetjük fel a meghívandó webmetódusunkat. Egyetlen JSON “dictionary”-t kell csak összeállítanunk.

dv:autofetch

Az autoFetch tulajdonság true-ra állításával adhatjuk meg, hogy a DataView az oldal betöltődésekor azonnal forduljon az adatforráshoz és töltse fel magát adatokkal. Ha ezt false-ra állítjuk, akkor nekünk kell meghívni a fetchData metódust, például így (feltételezve, hogy a fenti ul elemet elláttuk egy id=”list” attribútummal):

  $find('list').fetchData();

Kliens oldali adatkötés kódból

Természetesen itt is van lehetőség arra, hogy a HTML markupot és az adatkötést szétválasszuk, tehát a teljes adatkötést tisztán kódból végezzük el. Csupaszítsuk le a markupot (az előző cikkben bemutattam, hogyan lehet a {{}} elemektől megszabadulni, itt most csak az adatforrás kezelésére koncentrálok, ezért ezeket most meghagytam):

  <ul
    id="list"
    class="sys-template" >
    <li>
        {{ Name }} ({{ Capital }}) 
    </li>
  </ul>

Az adatkötést pedig az oldal inicializálásakor végezzük el, így:

  <script type="text/javascript">
    Sys.Application.add_init(appInit);
    function appInit()
    {
        $create(
            Sys.UI.DataView,
            {
              autoFetch: false,    // Hogy legyen lehetőségünk még inicializálni
              dataProvider: "Services/CountryService.svc",
              fetchOperation: "GetCountries",
              fetchParameters: { orderby: 'Name', asc: true }
            },
            null,
            null,
            $get("list")
        );
        // Ide jöhetne további inicializálás...
        $find('list').fetchData();
    }
  </script>

Ennyi, ki lehet próbálni, működni fog.

Rendezés

Miután rátettük a kezünket a fetchParameters tulajdonságra, semmi akadálya, hogy a felhasználó határozza meg, milyen sorrendben akarja látni az adatokat. Hogy egyszerűbb legyen az életünk, a rendezés adatait és a DataView vezérlőt kiemelhetjük globális fetchParams és dv változókba:

  var fetchParams = { orderby: 'Name', asc: true }
  var dv;
  Sys.Application.add_init(appInit);
  function appInit()
  {
      $create
( Sys.UI.DataView, { autoFetch: false,
dataProvider: "Services/CountryService.svc", fetchOperation: "GetCountries", fetchParameters: fetchParams }, null, null, $get("list") );
      dv = $find('list');
      dv.fetchData();
  }

Kellene még két metódus, amellyel gyorsan lehet rendezési szempontot és irányt váltani és amelyek azonnal frissítik a DataView vezérlőt:

  function sortBy(col)
  {
    fetchParams.orderby = col;
    dv.fetchData();
  }

  function sortAsc(dir)
  {
    fetchParams.asc = dir;
    dv.fetchData();
  }

Végül már csak UI elemekre van szükség ezeknek a függvényeknek a meghívásához:

  <a href="#" onclick="sortBy('Name')">Név szerint</a> 
  <a href="#" onclick="sortBy('Capital')">Főváros szerint</a> 
  | 
  <a href="#" onclick="sortAsc(true)">A-Z</a> 
  <a href="#" onclick="sortAsc(false)">Z-A</a>

Rakjuk össze mindezt egy oldalra és a felhasználó boldogan kattintgathat a linkekre, a háttérben a megfelelő sorrendben fognak letöltődni az adatok és azonnal meg is jelennek a böngészőben – természetesen AJAXosan frissítve az oldalnak csak az érintett részét.

A szép az egészben, hogy a tudomány nem áll meg itt: a rendszer képes arra is, hogy észrevegye, ha egy változó értéke megváltozik és automatikusan frissítse az értéket a felhasználói felületen. Folyt. köv.

A cikkhez tartozó forráskód letölthető innen.

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