C# - Windows-szerviz elérése ASP.NET alkalmazásból

forráskód letöltése
Web-alkalmazások készítésénél folytonosan uralkodik az a törekvés, hogy valamilyen hosszadalmas folyamat elvégzését ne az alkalmazás közvetlen felügyelete alatt végezzük, hanem valamilyen más módszerrel oldjuk meg az ilyen, a főszál működését akadályozó tevékenységek elvégzését. Ennek kapcsán bemutatunk cikkünkben egy példát arra, hogy miként oldható meg más alkalmazások elérése ASP.NET-ből, melyekkel az időigényesebb feladatok elvégeztethetők.
Mellékelt példa megnyitása előtt szükséges egy WebRemoting nevű virtuális könyvtár létrehozása, mely a példa könyvtárára mutat. Ehhez nyissa meg a mellékelt mappa Tulajdonság ablakát és itt a Webmegosztás lapon engedélyezze a mappa megosztását olvasási és parancsfájlok futtatási jogával.
Az alkalmazás futtatása előtt installálnia kell a program mappájának RWinService alkönyvtárában megtalálható szerviz-alkalmazást. Ezzel kapcsolatban olvassa el a cikk RWinService projekt című bekezdését.
Megoldás áttekintése
A bevezetőben említett másik alkalmazás jelen esetben egy Windows szerviz, melyet „megszólít” a Web-alkalmazás, majd a kapcsolat felépítése után meghívhatja annak tetszőleges funkciót, tetszőleges idő alatt elvégző metódusát.
A .NET futtatórendszer Remoting nevezetű szolgáltatásának felhasználásával teremtünk kapcsolatot az ASP.NET, és a szerviz alkalmazás között. A projektek mindegyikében meg kell adni referenciaként a .NET Remoting szolgáltatásának igénybevételéhez szükséges osztályokat tartalmazó névteret. Ehhez válasszuk a Project - Add reference menüpontot, majd a megjelenő ablakban a .NET lapon keressük elő a System.Runtime.Remoting elemet. A forráskódot tartalmazó állományok elején meg kell adnunk, hogy a névtér osztályai közül melyekre van szükségünk
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
A feladatban modellezzük a kapcsolatfelvételt, valamint a metódushívást, melynek azonban nem adunk komolyabb feladatot, csak egy karakterlánc visszaadásának elvégzését. A metódusban természetesen bármi megadható.
A WebRemoting mappában a Web-alkalmazás állományain kívül még két projekt állományai kaptak helyet. A RObject mappában találjuk meg annak az osztálynak a kódját, melyet regisztrálunk szerver-, és elérünk kliens oldalon. A RWinService mappában pedig a szerviz-alkalmazás kódját helyeztük el. Lássuk ezeket részletesen:
RObject projekt
A RemoteClass osztályban helyeztük el a GiveAnswer metódust, mely elvégzi a feladatot, vagyis a karakterlánc visszaadást. Fontos követelmény, hogy ezt a távoli elérés érdekében a MarshalByRefObject osztályból származtassuk. A meghívandó metódus pedig a következő:
public String GiveAnswer()
{
  return "A kapcsolat létrejött a kiszolgáló alkalmazással!";
}
A projektet lefordíthatjuk. A másik két projektben szükségünk van arra, hogy elérjük a létrehozott osztály, és a metódus deklarációját. Ennek érdekében a RObject névteret meg kell adnunk referenciaként a projektekben. Válasszuk ismét a Project - Add reference menüpontot, majd a megjelenő ablakban a Projects lapon jelöljük ki az RObject elemet.
RWinService projekt
A szerver szerepét betöltő szerviz elkészítését azzal kell kezdjük, hogy a hivatkozott névterek listájába a fent említett névterek mellett meg kell adnunk a RObject névteret is:
using RObject;
A szerviz alkalmazások indításakor elvégzendő feladatokat az OnStart metódusukban helyezzük el. Jelen esetben ez nem más, mint a TCP port használatának előkészítése. Regisztrálnunk kell egy TCP portot, melyen keresztül az alkalmazásunk elérhető lesz. Ehhez létrehozunk egy új TcpChannel osztályt, melynek konstruktorában adjuk meg a használni kívánt port számát:
TcpChannel tc = new TcpChannel(9001);
A ChannelServices osztály RegisterChannel függvényének segítségével regisztrálhatjuk ezt a portot az alkalmazásunk számára:
ChannelServices.RegisterChannel(tc);
Befejező lépésként regisztráljuk azt az osztályt, melynek függvényét elérhetővé kívánjuk tenni. Ehhez szükségünk lesz az RObject névtér RemoteClass osztályának típusára, Type formában.
Type t = typeof(RObject.RemoteClass);
A RemotingConfiguration osztály RegisterWellKnownServiceType függvényét felhasználva elvégezhetjük a regisztrációt. Itt első paraméterként megadjuk az osztály típusát, másodikként egy azonosító nevet, melyet a híváskor kell majd felhasználnunk, végül a hívás módjáról rendelkezhetünk.
RemotingConfiguration.RegisterWellKnownServiceType(t, "Add", WellKnownObjectMode.SingleCall);
Használatához viszont telepítenünk kell a többi szerviz alkalmazáshoz hasonlóan.
A telepítés menetét megkönnyítendő válaszuk ki a „WinService1.cs [Design]” lapot. Ha ez megvan, akkor a Properties ablak alsó részén látható lesz egy Add Installer link. Kattintsunk erre. Ennek hatására létrejön a projektünkhöz egy új forrás állomány ProjectInstaller.cs névvel. Ebbe automatikusan bekerül egy ServiceProcessInstaller és egy ServiceInstaller komponens, mely segít elvégezni a telepítést, eltávolítást.
Válasszuk a serviceInstaller1 komponenst és a DisplayName property-jének adjuk értékül a _RWinService szöveget.
Válasszuk most a serviceProcessInstaller1 komponenst, majd az Account property-be a LocalSystem elemet jelöljük ki.
Fordítsuk le az alkalmazást a Build – Build menüpont kiválasztásával. Itt most nem futtathatjuk a programot, hiszen ez egy szerviz alkalmazás, így azt csak az operációs rendszer futtathatja.
A tényleges telepítés elvégzéséhez még szükségünk lesz egy kis segédprogramra, mely része a Visual Studio.NET-nek. Ez az InstallUtil.exe lesz. Ennek kell paraméterként megadnunk a telepítendő szerviz alkalmazásunk EXE-jét elérési útvonallal. Ehhez indítsunk egy parancssort, méghozzá a Start - Programs - Microsoft Visual Studio.NET - Visual Studio.NET Tools - Visual Studio.NET Command Prompt menüponton keresztül. Erre a speciális parancssorra azért van szükség, hogy az InstallUtil alkalmazás bárhonnan elérhető legyen.
installutil C:\Test\RWinService.exe
Indítsuk el a Control Panel-ben lévő szerviz kezelő alkalmazást (Services), mely indítás után - megtalálva a DLL-t -, elvégzi a szükséges csatorna-inicializáló műveleteket.
Ha szeretnénk eltávolítani a szervizek közül az alkalmazásunkat, akkor ismét az InstallUtil.exe segédprogramot kell használnunk. Most viszont egy /u paramétert is kell használnunk.
installutil /u C:\Test\RWinService.exe
Az ASP.NET alkalmazás, mint kliens
A Web-alkalmazás WebForm1.aspx lapján elhelyezett gombbal teremtünk kapcsolatot a szerverrel, illetve hívjuk meg a metódust.
A RObject névtér elérése itt is szükséges, így adjuk meg itt is a hivatkozást:
using RObject;
A művelet elvégzéséhez ismét egy TcpChannel osztályra lesz szükségünk, valamint az Activator osztály GetObject függvényére. Ez utóbbi képes arra, hogy egy adott távoli objektumot aktiváljon, és arról egy referenciát visszaadjon. Első paraméterként az elérendő objektum típusát kell megadnunk itt is Type típusban. Második paraméterben egy kapcsolódási URL-t adunk meg, melyben a TCP protokollon keresztül elérjük az adott gépen futó, általunk választott porton figyelő alkalmazást.
TcpChannel tc = new TcpChannel();
ChannelServices.RegisterChannel(tc);
rc = (RemoteClass)Activator.GetObject(typeof(RObject.RemoteClass), "tcp://localhost:9001/Add");
Majd meghívjuk a távoli objektum GiveAnswer metódusát. A visszakapott karakterláncot megjelenítjük egy Label kontrolon:
message.Text = rc.GiveAnswer();
A konkurens kérések közül egyszerre természetesen egy időben csak egy használhatja az adott kapcsolatot, így a művelet végeztével azt fel kell szabadítani, hogy később más kérések is kiszolgálhatók legyenek. Ehhez a ChannelServices osztály UnregisterChannel metódusát kell meghívnunk, melynek működése ellentétes a fenti művelettel, azaz törli a csatornaregisztrációt:
ChannelServices.UnregisterChannel(tc);