Microsoft ASP.NET AJAX 1.0 je právě ve stádiu Release Candidate (RC), nastává tedy správný čas pro bližší seznámení… ;-)
I když většinu potřebných AJAX features najdeme hotových ve formě server controlů, kdy nejsme nuceni napsat ani jediný řádek JavaScriptu, není od věci vědět, že i explicitní volání webových služeb je z ASP.NET AJAXu velmi jednoduché a snadno použitelné (obzvláště pokud poznáme, že je to prakticky stejné, jako přístup k webovým službám na straně serveru, resp. z .NET Frameworku).
Zpřístupnění webové služby
Základem každé AJAX-enabled stránky je control ScriptManager, který zajišťuje správu klientského AJAXového JavaScriptu. Zpřístupnění webové služby pak není nic jiného, než vytvoření ServiceReference na naší webovou službu
<asp:ScriptManager ID="ScriptManager" runat="server"> <Services> <asp:ServiceReference Path="~/MyWebService.asmx" /> </Services> </asp:ScriptManager>
Princip je to prakticky obdobný, jako v případě webových služeb na straně serveru (resp. v .NET aplikacích). Lze to přirovnat k přidání Web Reference do projektu ve Visual Studiu, nebo k použití utility wsdl.exe k vygenerování proxy třídy pro přístup k webové službě. Jediným zásadním rozdílem je, že lze takto přistupovat pouze na vlastní webové služby – tedy webové služby, které jsou součástí naší aplikace. Pokud bychom potřebovali přístup k externím webovým službám, není však problém vytvořit bridge prostřednictvím vlastní proxy webové služby.
Vraťme se však k našemu příkladu, dejme tomu, že webová služba ~/MyWebService.asmx by definovala jednu metodu
using System; using System.Data; using System.Web; using System.Collections; using System.Web.Services; using System.Web.Services.Protocols; using System.ComponentModel; using System.Web.Script.Services; namespace MyNamespace { [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class MyWebService : System.Web.Services.WebService { [WebMethod] public string GetServerTime(string serverName) { return serverName + ": " + DateTime.Now.ToShortTimeString(); } } }
…jedná se o úplně klasickou webovou službu, která má navíc jen atribut [ScriptService] (jinak lze však tuto webovou službu využít jako kteroukoliv jinou). Atribut ScriptService zajišťuje, že nový handler .asmx souborů, s kterým ASP.NET AJAX přichází, dokáže při požadavku GET MyWebService.asmx/js vrátit vygenrovaný JavaScript s příslušnými proxy objekty pro práci s webovou službou. Ve skutečnosti totiž control ScriptManager přidá do stránky kód
</script src="MyWebService.asmx/js" type="text/javascript">
Pomocí atributu [ScriptMethod] u jednotlivých metod jsme navíc schopni řídit další detaily, např. formát, kterým spolu klientská a serverová část komunikují. Ve výchozí podobě totiž není komunikace na bázi XML, nýbrž v podobě JSON (JavaScript Object Notation), např.:
{"prefixText":"M","count":3} ["Michal", "Mirek", "Milan"]
Volání metod webové služby
Samotné volání metod webové služby je už hračkou, ASP.NET AJAX nám totiž vygeneruje objekt odpovídající webové službě, v namespace odpovídající webové službě a s metodami dle webové služby. Nejjednodušší volání tak může vypadat např.
<script type="text/javascript"> MyNamespace.MyWebService.GetServerTime('MyServer'); </script>
Musíme si však uvědomit, že veškeré AJAXové requesty jsou asynchronní, tedy musíme metodě říct, jakou funkci má zavolat po dokončení operace (přijetí odezvy od serveru) – výše uvedená nejjednodušší forma se tak moc často neuplatní. Nemáme-li totiž nastaven defaultní callback, pak nemáme jak převzít výsledek a jedná se prakticky jen o jednosměrnou komunikaci (navíc bez success-checkingu).
Další možností je tedy přidat jako další parametr metody funkci, která se má zavolat v okamžiku přijetí odezvy serveru, a která převezme a zpracuje výsledek. Parametrem funkce je výsledek volání metody přijatý v odezvě serveru.
<script type="text/javascript"> MyNamespace.MyWebService.GetServerTime('MyServer', OnComplete); function OnComplete(result) { alert(result); } </script>
Další vhodnou možností je přidat jako další parametr volání metody funkci, která se má zavolat v případě neúspěchu, v případě chyby:
<script type="text/javascript"> MyNamespace.MyWebService.GetServerTime('MyServer', OnComplete, OnError); function OnComplete(result, context) { alert(result); } function OnError(result) { alert(result.get_message()); } </script>
Jako poslední parametr lze přidat ještě určitý context, prostě obecná data, která se mají předat do metody OnComplete (neposílají se na server):
<script type="text/javascript"> MyNamespace.MyWebService.GetServerTime('MyServer', OnComplete, OnError, 'context'); function OnComplete(result, context) { alert(context); alert(result); } function OnError(result) { alert(result.get_message()); } </script>
Webové metody ve stránce
Abychom nemuseli vždy vytvářet úplnou webovou službu, máme též možnost jednoduché lokální metody umístit přímo do třídy samotné webové stránky (do kódu stránky), odekorovat je atributem [WebMethod] a následně k nim můžeme přistupovat prostřednictvím objektu PageMethods, aniž bychom museli jakokouliv webovou službu registrovat. Musíme jen povolit přepínač EnablePageMethods ScriptManageru:
public partial class _Default : System.Web.UI.Page { [System.Web.Services.WebMethod] public static string GetHelloWorld() { return "Hello world!"; } }
<script type="text/javascript"> PageMethods.GetHelloWorld(OnHWComplete); function OnHWComplete(result) { alert(result); } </script>
Webová metoda uvnitř stránky musí být statická!
Shrnutí
Explicitní volání webových služeb z klientské strany je velmi silnou zbraní ASP.NET AJAXu, pomocí které lze realizovat prakticky libovolnou AJAX funkčnost pro kterou nenajdeme vhodný hotový control. Pokud si navíc uvědomíme, že webová služba může pracovat prakticky s libovolnými serializovatelnými datovými typy (včetně DataSetu!), pak tímto dostáváme velmi příjemný nástroj pro klientské skriptování.