.Net 2 előadás jegyzet – 8. óra
1.oldal
.NET Microsoft .Net Framework és programozása II. Előadás jegyzet Előadó: Pócza Krisztián ELTE,2012
Web service, WCF (és Remoting) Az e-beszámoló és a Rendszer • e-beszámoló = céges beszámoló (mérleg, eredmény kimutatás, stb.) ami elektronikus, 2009. május 1-től kötelező, IRM, KIM • A Rendszer feladata: > ÁNYK űrlap biztosítása az Ügyfélkapun történő e-beszámoló beküldéshez > Az e-beszámolók fogadása a Központi Rendszertől, majd validálása, tárolása > Az ügyfelek értesítése > Publikációs-, és keresőfelület biztosítás (http://www.e-beszamolo.kim.gov.hu/) > A beszámolók NAV felé való továbbküldése > Elektronikus számlák kiküldése > Belső adminisztrációs felület biztosítása
(Forrás: www.atigris.hu/pic/nworkshop/NWS2k11-e-besz.pdf)
.Net 2 előadás jegyzet – 8. óra
2.oldal
Web service A .NET -ben is van lehetőség web service -ek létrehozására. A web service -ek az Internetre kitett és ott futó szolgáltatások, amik kliens gépekről hívhatók. Ez a kommunikáció egy szabványos protokollja. Távoli hívásra épül (elküldünk egy kérést, ott feldolgozzák, majd kapunk rá egy választ). Nem kell mást tennünk, csak a WebService osztályból származtatni. Hozzunk létre egy új WebSite -ot, de válasszuk az ASP.NET WebService projekt típust! Alapból létrejön egy HelloWorld() eljárás, aminek van egy [WebMethod] Attribute –ja. Ez azt jelzi, hogy publikáljuk az eljárást a kliensek felé. Az új class alapból megkapta még a [WebService(Namespace = "http://tempuri.org/")] attributumot is, ami tempuri.org névtérbe rendezi a service -ünket (ezt érdemes is átírni egy megfelelőbbre, ami egyedi). Észrevehető még, hogy most egy Service.asmx nevű és .asmx kiterjesztésű file -unk van. Ez jelzi, hogy web-szolgáltatást írunk. Ha a Service.asmx mögé beírjük a ?wsdl-t a böngészőben, akkor megkapjuk az eljárásaink WSDL (WebService Description Language) leírását. Ez egy XML alapú szabványos leíró nyelv, ami az eljárásaink paramétereit, visszatérési étékeit, stb. írja le azért, hogy akik használni akarják a szolgáltatást, azoknak legyen információjuk a használatról. Ez alapján a kliens oldal le tudja „gyártani” azokat a formokat, amik a szerveren megvannak (jobb mintha letöltené). [WebService(Namespace = "http://dotnet.elte.org/FirstService")] // A namespace legyen egyedi, de nem fontos, hogy létező URL –re mutasson public class Service : System.Web.Services.WebService { public Service () { //Uncomment the following line if using designed components //InitializeComponent(); } [WebMethod] public string HelloWorld() { return "Hello World"; } [WebMethod] public int Add(int x, int y) { return x + y; } }
Hogy használhassuk a Service –ünket, csináljunk egy új projektet(Consol Application) és adjuk hozzá a solution -höz. Majd adjunk hozzá egy WebReference -t a szolgáltatásunkra. class Program { static void Main(string[] args) { Service sv = new Service(); Console.WriteLine(sv.Add(1, 2).ToString()); } }
.Net 2 előadás jegyzet – 8. óra
3.oldal
A fenti kód elég is a teszteléshez. Persze előbb a környezetben érdemes egy jobb klikkel alapértelmezettnek választani a TestProjektet. Fontos megjegyezni, hogy a WebService (ugyan úgy, mint a http protokoll) állapotmentes, azaz két egymást követő hívás nem tud egymásról. De itt is van Session-kezelés és Cache lehetőség, valamint Global.asax is. Híres publikus web service Amazon könyvkeresője, beépíthető az alkalmazásunkba. WCF - Windows Communication Foundation .NET 3.0-ban volt először. A kommunkiáció szabványos formája(hasonló, mint a COM, OLE…) A WCF segítségével szolgáltatás-orientált alkalmazásokat tudunk létrehozni, amelyek akár más platformon futó alkalmazásokkal is kommunikálhatnak. Egy egységes programozási modellt nyújt a fejlesztők számára. Így ugyanabban a környezetben tudunk fejleszteni, ha web szolgáltatást, enterprise web szolgáltatást vagy épp .NET Remoting alkalmazásokat akarunk készíteni. Fontos, hogy a szolgáltatás-szerződéseket el lehet választani az adatszerződésektől. WCF – ABC (Address + Binding + Contracts) - Address: adott szolgáltatás hol érhető el? (pl. http cím) - Binding: adatformátum – milyen adatformátumban menjenek az adatok a hálózaton? (pl: TCP, HTTP, WSHTTP, message queue – nem mindegyik szabványos és nem mindegyik kompatibilis) - Contracts: külön van adat- és szolgáltatásszerződés (és még néhány speciális fajta) A szolgáltatás contract a távoli gépen példányosul. Az adat contract a gépeden átalakítja, majd átküldi és ott visszaalakítja az adatot. A szolgáltatás contract - marshal by reference, az adat contract - marshal by value. Hol fognak futni ezek a programok? – a web szerveren memory leak pl. ki van védve így. Hátrányok: IIS szerver sok dolgot nem tud, nem támogat (pl. bináris átvitelt webservice -nél). Kiterjesztés: tudunk saját binding -okat csinálni, illetve a már meglévőket módosítani, kiegészíteni (adatcsomag méretet, time out értéket, stb…). Lehet behaviour -öket írni plusszban, amik hivás előtt vagy után futnak le (pl. authetnikáció előtt legyen az, hogy…).
.Net 2 előadás jegyzet – 8. óra
4.oldal
A WCF-ről további leírást találhatunk itt: http://msportal.hu/blogs/turczy_attila/archive/2008/05/13/windows-communicationfoundation-elm-233-leti-h-225-tt-233-r.aspx Példa program: WCFExample (tárgy honlapján) Rétegek: - szolgáltatás - entities (assambly) - data access - kliens (GUI) - WCF host (hosting szolgáltatás) - ez most csak konzolos - tesztelő modul Data access –hez script –ek, amik létrehozzák. LinQ -t használunk az adatrétegnél. Szolgáltatás réteg – műveletek definiálása (Contract rész) Entities részben – adatszerződések (Contract rész) Binding rész: Application config – végpontokat kell definiálni <service name="Services.CountryService" behaviorConfiguration="debug"> <endpoint address="net.tcp://localhost:8080/Interfaces/CountryService/netTcpBinding" binding="netTcpBinding" bindingConfiguration="bigNetTcpBinding" contract="Entities.Interfaces.ICountryService" />
Ugyanitt állíthatók a behaviour -ök.
<serviceDebug includeExceptionDetailInFaults="true" /> <serviceThrottling maxConcurrentCalls="1000" maxConcurrentSessions="1000" maxConcurrentInstances="1000" />
Entities alatt van Proxy - CountryServiceProxy (Var mire jó? Kitalálja hogy a baloldalon lévő változónak mi lesz a típusa) Ha sikeresen végrehajt hívást, akkor egy dedikált konkurens példányt hoz létre. Program.cs-ben kód: Lambda expression formátum. Csináljunk hozzá szép, Webes alkalmazást (WCFServiceApplication)! Neve: WCFWebHost. Ott Web.Conf átírása. (ill törölni, ami nem kell – webservice -hez tartozók) <system.serviceModel> <services> <service behaviorConfiguration="WCFWebHost.CountryServiceBehavior" name="Services.CountryService"> <endpoint address="" binding="wsHttpBinding" contract="Entities.Interfaces.ICountryService">
.Net 2 előadás jegyzet – 8. óra
5.oldal
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<serviceBehaviors> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" />
Remoting (oldschool, deprecated) A Remoting a Webservice -ektől eltérően csak .NET-es alkalmazások között alkalmazható, de megvan az az előnye, hogy sokkal gyorsabb. Az alkalmazások közti kommunikáció többféle csatornán keresztül is mehet, TCP, HTTP, IPC (Inter Process Communication), amiből az utóbbi, csak lokális gépen alkalmazható. Mielőtt az adatokat a csatornára tennénk meg kell őket formázni. Erre használhatók a beépített Formatter -ek (Binary, SOAP), de lehet User Defined Formatter -t is irni. A kommunikációt az alábbi ábra mutatja:
Client
Server Server Object
Client Application Object Proxy
Remoting
Remoting
Formatter
Formatter
Listener CHANNEL
.Net 2 előadás jegyzet – 8. óra
6.oldal
Kommunikáció: A kliens számára a szerver objektumot érdemes proxy -ként kezelni, mert ekkor könnyebben skálázható az alkalmazás. A kliens alkalmazás a proxy objektummal kommunikál, ami majd elintézi a kommunikációt. A kliensnek a szerver olyan, mintha azon a gépen lenne, mint az alkalmazás. A formatter megformázza (Binary, SOAP, User Def.) az adatot (Document) mielőtt a csatornára bocsátaná. A User oldalon Szerializáció átvitel, majd a Server oldalon Deszerializáció történik. Objektum típusok A .NET -ben az egyik process -ben létrehozott objektum nem látható egy másik process -ből, vagy a hálózaton keresztül. Mégis szeretnénk bizonyos objektumokat „nem lokálisként” kezelni. Erre a következő lehetőségek vannak:
Marshal By Refernce (MBR) Más néven anchored object. Azt jelenti, hogy az objektum maga le van „horgonyozva” és soha nem utazik a hálozaton keresztül. Ha eljárásokat akarunk hívni rajta, akkor az eljárások mozognak a hálón. Ez csak akkor ad elfogadható megoldást, ha kevésszer hívunk rajta metódust. Ezek az üzleti szolgáltatások. Marshal By Value (MBV) Más néven Üzleti Objektum, unanchored object (Business Object, BO). Ezek a típusok tudnak közlekedni a hálózaton, de csak a .NET -es szerializáció segítségével. Ezért ezeket az objektumokat tudnia kell a keretrendszernek szerializálni. Ezt a [Serializable()] attributummal tudjuk elérni. (illetve ha magunk akarjuk támogatni a szerializációt, akkor megvalósítjuk az ISerializable interface –t).
Aktiválási módok (MBR) Szerver aktivált: Singleton A server oldalon egyetlen egy objektum szolgál ki minden kliens oldalról beérkező kérést. SingletonCall Minden híváskor létrejön egy objektum a szerver oldalon, ami elintézi a kliens-kérést, majd egy bizonyos timeout után felszabadul. Az első megoldás kevésbé erőforrás pazarló, de nagyobb az esély a konkurencia problémákra. A másodikat implementálni is könnyebb. Kliens aktivált: Minden kliens egy dedikált példányt kap és ezzel dolgozik.
.Net 2 előadás jegyzet – 8. óra
7.oldal
WCF Példa Kezdjük az entitásokkal: Entities.Interfaces: ICountryService.cs Leírja a szerződést a szerver és a kliens között. [ServiceContract(Namespace="http://avalon.inf.elte.hu/edu/net2/WCFExample/svc")]
Szolgáltatási szerződés egy névtérrel. Alatta láthatunk néhány operációt. Amelyik előtt [OperationContract] található, azt elérheti majd a kliens. Country.cs [DataContract(Namespace = "http://avalon.inf.elte.hu/edu/net2/WCFExample/data")]
Ez az alap szerződés. [DataMember] -ekkel pedig fel van tüntetve, hogy mi az amit át akarunk küldeni az éteren. ServiceFactory.cs Két binding található benne: internal static ICountryService GetCountryService() internal static ICountryService GetCountryServiceOverHttp()
Client: Program.cs Ez egyrészt meghívogatja a CountryServiceProxy.AddCountry -t, illetve felkonfigurálja a kliensoldalt. WCFHost: Program.cs ServiceHost serviceHost = new ServiceHost(typeof(CountryService))) De vajon mi az a CountryService? Ez a Services –ben található elrettentő példa adatelérési műveletek implementációjára megvalósítja az ICountryService -t. Az összes szolgáltatása
publikus a kliensek számára. Hosztolható akár konzolból, akár webről. References – System.ServiceModel Itt a Services –ek között tüntetjük fel azokat a szolgáltatásokat, amiket publikálni akarunk. Milyen szerződést? Milyen címen? Milyen átvitellel? (Újabb .NET verziókban létezik jobb megoldás is, ahol nem kell binding -olni az összes service host –ot) HF.: Hogyan működik a webes elérés?
.Net 2 előadás jegyzet – 8. óra
8.oldal
RemotingExample Ez egy többrétegű példaalkalmazás a remoting technológia bemutatására. Maga a program nem sokat csinál, diákok nevének és credit pontjainak a nyilvántartására képes. Az out könyvtárban találunk egy Server és egy Client könyvtárat, amiben a nevüknek megfelelő projektek kódja van. Elindítva előbb a szervert, majd utána klienst látható is a működés. Látható hogy SingleCall esetben nem növekszik a beérkezett hívások száma (ezt el is várjuk tőle), míg a Singleton hívásnál egyesével nő. Tehát a program működik, nézzünk bele a kódba:
Server Az alábbi using -ok a Remoting helyes működéséhez kellenek : using using using using using
System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp; System.Runtime.Remoting.Channels.Http; System.Runtime.Remoting.Channels.Ipc;
Az első két eljárás a Main() -ben a remoting felkonfigolására használható, ami megtehető programból, vagy config file -ból, nyilván az utóbbi rugalmasabb.
<system.runtime.remoting>
Itt húzzuk fel a kommunikációs csatornákat, amit fentebb említettünk, egy TCP, http és egyet az IPC-hez: <serverProvider>
Ez a rész írja le a szolgáltatások konfigját. Meg kell adnunk az URI-t (Universal Resource Identifier), amiből majd a teljes URL fog kialakulni. Meg kell adnunk az objektum típusát valamint azt, hogy Singleton vagy SingleCall szolgáltatást akarunk-e. Az hogy mikor szerver aktivált azon múlik, hogy a szerver vagy a kliens mondja meg, hogy Singleton vagy SingleCall módon akarunk kommunikálni. <service>
.Net 2 előadás jegyzet – 8. óra
9.oldal
<wellknown mode="SingleCall" type="RemotingExample.BusinessLogic.CreditCalculator, BusinessLogic" objectUri="RemotingServer/SingleCallExample" /> <wellknown mode="Singleton" type="RemotingExample.BusinessLogic.CreditCalculator, BusinessLogic" objectUri="RemotingServer/SingletonExample" /> <service> <wellknown mode="Singleton" type="RemotingExample.BusinessLogic.AsyncExample, BusinessLogic" objectUri="RemotingServer/AsyncExample" /> A CreditCalculator egy MBR objektum, ami abból is látszik MarshalByRefObject -ból származtat. Minden public metódusába be lehet
hívni (itt nem
kell WebMethod attributummal jelölni, mint a WebService -eknél). A diákok adatai XML -ben vannak tárolva, a kezelést a StudentXMLStore végzi, ami egy ContextBoundObject. Ez azt jelenti, hogy minden hívást szinkronizál, ha a Synchronized attribútumot feltüntetjük az osztály előtt. A creditek számolása is kölcsönös kizárással történik, erre jó az Interlocked.Increment(ref _callCounter). A bekonfigurálás után a Server működése elég egyszerű: Megvárja, hogy belehívjanak a kliensek a beregelt szolgáltatás publikus metódusaiba. Majd egy ReadKey() után befejezi a működését.
Client A klienst programból konfigoljuk fel: ProgramaticConfiguration() Ha el akarjuk érni a creditCalculator -t létre kell hoznunk egy példányát, de most (mivel ez távol van) az Activator segítségével történik. creditCalculator = (ICreditCalculator)Activator.GetObject(typeof(ICreditCalculator), "tcp://localhost:8081/RemotingServer/SingleCallExample");
Ezután csak létrehozunk egy Student -et (naná, hogy Chuck Norris –t!), majd adunk néhány kreditet neki, hogy lássuk a működést. Miután létrehoztuk a távoli objektumot, olyan egyszerűen kezelhetjük remotingon keresztül, mintha csak lokális lenne. A ClientNoIntf kliensben is hasonló dolgok törtéennek, azonban lényeges különbség, hogy most hagyományos módon hozzuk létre a Calculator-t, ICreditCalculator creditCalculator = new CreditCalculator();
.Net 2 előadás jegyzet – 8. óra 10.oldal Ezzel az a baj, hogy a new -val történő létrehozáshoz ismerni kell a CreditCalculator kódját. Ez azért baj, mert Reference -t kell tenni a BusinessLogic –ra, amit a legkevésbé sem szeretnénk publikálni a kliensnek. Ez nem biztonságos és OOP megoldás. Ezért kell az Activator és a GetObject (habár ez lassabb, de nem sértünk vele objektum orientált elveket). Ekkor a keretrendszer megkeresi a beregisztrált objektumot, ami implementálja az interface -t és abból ad vissza példányt. Ilyenkor nem kell reference a BusinessLogic -ra csak a DataObjects -re A RemotingAsyncClient -ben található egy [OneWay] attributum, ami optimalizálásra is jó. Jelentése annyi, hogy meghívom a szerver oldalon az eljárást és nem foglalkozom a válasszal, nem várom meg a lefutást. Ekkor az Exception -ökről sem értesülök.