C# - Egyedi filterek deklarálása Web-szervizekben

forráskód letöltése
A .NET Framework System.Web.Services névterének osztályait és lehetőségeit kiegészítendő a Microsoft elérhetővé tett egy névteret Web Services Enhancements for Microsoft® .NET (WSE) néven. Az 1.0-ás verzió után most megjelent a WSE 2.0 verziója, mely számos újdonsággal bővült. Cikkünkben a névtér új képességeiből ragadunk ki egyet, és mutatjuk be használatát gyakorlati szemszögből.
A mellékelt példa megnyitása előtt szükséges egy CFilterService nevű virtuális könyvtár létrehozása, mely a példa könyvtárában található CFilterService mappára mutat. Ehhez futtassa le a mellékelt CreateVD.js parancsállományt. A mellékelt példa használatához telepítenünk kell a Microsoft WSE 2.0 csomagot. Ennek elvégzéséhez olvassa el a Kezdeti lépések című fejezetet.
Kezdeti lépések
A Microsoft által elkészített csomag a Web Services Enhancements for Microsoft .NET nevet viseli, és cikkünk írásakor a következő webcímen volt elérhető, mely azóta természetesen megváltozhatott:
http://www.microsoft.com/downloads/details.aspx?displaylang=en&familyid=21fb9b9a-c5f6-4c95-87b7-fc7ab49b3edd
Letöltve az állományt (WSE20TP.exe) telepítenünk kell a .NET Framework alá. Az öntelepítő állomány erről gondoskodik, a használható .DLL állomány (Microsoft.Web.Services.dll), és a kapcsolódó dokumentáció alapértelmezésben a következő mappába kerül: %winroot%:\Program Files\Microsoft WSE\v2.0\.
A telepített assembly bekerül a globális assembly-listába, így amikor referenciaként megadjuk alkalmazásainkban, akkor a globális palettáról kell kiválasztanunk, nem pedig valamilyen alternatív mappából.
Web-szerviz létrehozása
A szervizalkalmazások világában megszokhattuk, hogy a kommunikáció SOAP üzenetek formájában történik. A WSE új verziójának segítségével deklarálhatunk filtereket a kimenő és a kliensektől érkező üzenetekhez. A filterekben megadható, hogy milyen formában kerüljenek feldolgozásra az üzenetek. A ki-, és beérkező üzenetek filterei a Pipeline osztállyal reprezentált objektumban kerülnek elhelyezésre.
Mind a kliens, mind pedig a szervizalkalmazás saját filterrel rendelkezhet, mindegyik filter típushoz megtalálható a megfelelő ősosztály a Microsoft.Web.Services névtérben. A kliensalkalmazás a kimenő, míg a szervizalkalmazás a beérkező üzeneteket képes szűrni, vagyis valamilyen szempont szerint analizálni az üzenetet.
A szervizalkalmazás egyetlen webes metódussal rendelkezik, mely a kliensalkalmazásban megadott szöveget adja vissza abban az esetben, ha az üzenet rendelkezik a SAMPLETEXT nevű attribútummal. Egyébként egy, a hiányra utaló sorral tér vissza.
[WebMethod]
public string GetText()
{
  SoapContext requestContext = RequestSoapContext.Current;
  string text = requestContext["SampleText"] as string;
  if (text != null)
  {
    return "A küldött karakterlánc: " + text;
  }
  return "A küldött csomag nem tartalmaz szöveginformációt!";
}
A szervizhez létrehoztunk egy filtert CInFilter néven, melynek ProcessMessage metódusa elemzi az üzenetet. A metódusban kibontja a SOAP üzenet borítékját, majd keresi benne a megfelelő fejlécet (MyHeader).
XmlElement soap_header = envelope.Header;
XmlNodeList nodes = soap_header.GetElementsByTagName(header_name,uri);
Amennyiben az üzenet egy ilyet tartalmaz, akkor megkeresi benne a SAMPLETEXT attribútumot. Ha talál ilyet – vagyis a kliensben megadtuk a szöveget –, akkor a szerviz el tudja érni azt a GetText metódusban.
XmlElement cHeader = nodes[0] as XmlElement;
XmlAttribute text_attribute = cHeader.Attributes[attribute_name,uri];
...
envelope.Context["SampleText"] = text_attribute.Value;
A szervizalkalmazás Web.config állományában el kell helyezni néhány konfigurációs bejegyzést a megfelelő működés érdekében.
Elsőként regisztráljuk a Microsoft.Web.Services névteret.
<configSections>
    <section name="microsoft.web.services" type="Microsoft.Web.Services.Configuration.WebServicesConfiguration, Microsoft.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
A következő lépés megadni a szerviz által használt filter osztályát.
<microsoft.web.services>
  <filters>
    <input>
      <add type="CFilterService.CInFilter,CFilterService" />
    </input>
  </filters>
</microsoft.web.services>
Majd még egy bejegyzésre szükségünk van ahhoz, hogy a szerviz használhassa a HTTP protokollt.
<webServices>
  <soapExtensionTypes>
    <add type="Microsoft.Web.Services.WebServicesExtension, Microsoft.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" />
  </soapExtensionTypes>
</webServices>
A kliensalkalmazás
A COutFilter osztály lesz a kliensalkalmazás kimenő üzeneteit kezelő filter. A ProcessMessage metódusban megvizsgáljuk a SOAP kontextust, és a SampleText attribútumban található szöveget elhelyezzük a CreateHeader metódussal létrehozott fejlécben. Ezt küldjük el a szervizalkalmazásnak.
public override void ProcessMessage(SoapEnvelope envelope)
{
  string text = envelope.Context["SampleText"] as string; 
  if (text != null)
  {
    XmlElement soap_header = envelope.CreateHeader();
    soap_header.AppendChild(CreateHeader(soap_header,text));
  }
}
A kliensben egy webes referencia hozzáadásával hozzuk létre a szerviz eléréséhez szükséges proxyt. Ennek eredményeképpen a Reference.cs állományban lesz megtalálható a proxy deklarációja.
A KÜLDÉS gomb megnyomásával példányosítjuk a proxy objektumot.
localhost.Service proxy = new localhost.Service();
Létrehozunk egy példányt a filter osztályából.
proxy.Pipeline.OutputFilters.Add(new COutFilter());
Ha a jelölőnégyzet jelölt, akkor a kontextust reprezentáló objektumban elhelyezzük a szöveget, melyet a szövegmezőben megadtunk.
proxy.RequestSoapContext["SampleText"] = textBox2.Text;
Ellenkező esetben nem. A filter ettől függően helyezi el a fejlécben a szöveget, vagy hagyja ki onnan azt.
Majd meghívjuk a GetText metódust.
textBox1.Text = proxy.GetText();