Järgevalt väljatoodud koodi ja konfiguratsiooninäited on pärit lähtekoodis näitest Examples\Calculus .
Klientrakenduse ehitamine
Generaatori kasutamine
Selleks et päringuid xtee teenuste poole teha, tuleb kõigepealt valmis genereerida wsdl-ist struktuurid.
Avades Xtee Generaatori, tuleb sisestada dto-de ja serialiseerijate väljundite ning wsdli asukohad. Wsdli asukoht võib olla nii veebiaadress kui ka asukoht failisüsteemis, mõlemaga saab generaator hakkama. Samuti ei pea olema erinev dto-de ja serialiseerijate genereerimise asukoht, see võib olla ühesugune.
Kui genereerimine on õnnestunud, siis tuleb väljundist luua klass teegi projekt ja ära kompileerida (kui dtod ja serialiseerijad olid erinevatesse kataloogidesse paigutatud siis 2 projekti).
Vahemärkuseks, et generaatoril on konfiguratsiooni fail (Seadistus.xml), kuhu saab kirjeldada geneerimiseks argumendid ning mida saab valida vahendil olevast rippmenüüst. Näiteks nii:
<keha xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<item xsi:type="tns:XteeGenConfiguraton" xmlns:tns="http://XteeGen/XteeGenConfiguraton.xsd">
<Name xsi:type="xsd:string">Wsdl1</Name>
<WsdlPath xsi:type="xsd:string">http://local/app.wsdl</WsdlPath>
<ModelOutputFolder xsi:type="xsd:string">C:\app1</ModelOutputFolder>
<ImplOutputFolder xsi:type="xsd:string">C:\app1</ImplOutputFolder>
<GenerateOperationsNamely xsi:type="xsd:boolean">true</GenerateOperationsNamely>
</item>
<item xsi:type="tns:XteeGenConfiguraton" xmlns:tns="http://XteeGen/XteeGenConfiguraton.xsd">
<Name xsi:type="xsd:string">Wsdl2</Name>
<WsdlPath xsi:type="xsd:string">c:\\app2.wsdl</WsdlPath>
<ModelOutputFolder xsi:type="xsd:string">C:\app2</ModelOutputFolder>
<ImplOutputFolder xsi:type="xsd:string">C:\app2</ImplOutputFolder>
<GenerateOperationsNamely xsi:type="xsd:boolean">true</GenerateOperationsNamely>
</item>
</keha>
GenerateOperationsNamely element konfiguratsioonis on igand vanemast versioonist kus
meetodite signatuurid genereeriti kõik ühe nimega (Execute) mis aga tekitas probleeme sellega
et operatsioonide hulgas võib olla mitu sama sisendi/väljundiga operatsioone ja geneeruv kood seega ei komileeru. Soovitaks alati selle elemendi väärtuse tõesena hoida, siis klientrakendusele genereeruva teenuse kliendi meetodid nimetatakse wsdlis olevate operatsioonide nime järgi ja nii ei tohiks konflikte tekkida.
Klientrakenduse ülesseadmine
Xtee päringu väljakutsumiseks on vaja lisada rakendusse genereeritud dll-id ja Xtee.Core.dll (Lisaks log4net.dll).
Seejärel saab juba kirjutada päringu, mis võib välja näha näiteks selline:
namespace Client
{
class Program
{
static void Main(string[] args)
{
//CalcAdapter on pärit genereeritud struktuuride teegist
var client = new CalcAdapter();
decimal result = client.Add(new Variables(3, 4)).Value;
result = client.Multiply(new Variables(3, 4)).Value;
result = client.Subtract(new Variables(3, 4)).Value;
Console.WriteLine(result);
}
}
}
Selleks et päringud reaalselt ka tööle hakkaksid, on vaja rakendus konfigureerida.
Konfiguratsiooni failis tuleb registreerida xtee sektsioon selliselt:
<configSections>
<section name="xtee.configuration" type="Xtee.Core.Client.Config.ClientConfigurationSection, Xtee.Core"/>
</configSections>
ning kliendi konfiguratsioon minimaalses mahus selliselt:
<xtee.configuration proxyURL="http://localhost/adapter.asmx">
<xteeTypeAssemblies>
<clear/>
<add assemblyName="GenereeritudDtoDllNimi"/>
<add assemblyName="GenereeritudSerialiseerijadDllNimi"/>
</xteeTypeAssemblies>
</xtee.configuration>
Kindlasti tuleb registreerida genereeritud dll-id, nagu näites, muidu päringud tööle ei hakka.
Xtee kliendi konfiguratsiooni (xtee.configuration) võimalikud atribuudid on:
atribuut | väärtus |
proxyURL | Teenuse url mille vastu päringud sooritatakse |
storeMessages | (true/false) Kas sõnumid salvestada või mitte (vaikimisi:false) |
storagePath | asukoht kuhu sõnumid salvestada, võib olla nii relatiivne kui absoluutne rakenduse suhtest |
timeout | saab täpsustada kaua oodatakse enne kui päring katkestatakse, ooteaeg on millisekundites (vaikimisi : 100000 (1 min 40 sek)) |
objectType | sõnumi client elemendi attribuut, saab vaikimisi määrata väärtuse, mis päises kaasa antakse |
xRoadInstance | sõnumi client elemendi element, saab vaikimisi määrata väärtuse, mis päises kaasa antakse |
memberClass | sõnumi client elemendi element, saab vaikimisi määrata väärtuse, mis päises kaasa antakse |
memberCode | sõnumi client elemendi element, saab vaikimisi määrata väärtuse, mis päises kaasa antakse |
subSystemCode | sõnumi client elemendi element, saab vaikimisi määrata väärtuses, mis päises kaasa antakse |
userId | sõnumi element, saab vaikimisi määrata väärtuse, mis päises kaasa antakse |
issue | sõnumi element, saab vaikimisi määrata väärtuse, mis päises kaasa antakse |
message-path-format | Võimaldab kohandada salvestatavate sõnumite asukohta võtmesõnade abil. |
| Vaikeväärtus on: [service]\[year]\[month]\[day]\[personalcode]\[year]-[month]-[day]__[timeofday]__[ms].[type].txt mille puhul faili asukohaks määratakse näiteks : ...\colors.mix.v1\2013\10\23\38056489521\2013-10-23__21-04-22__012847@127.0.0.1.request.txt. Võimalikud võtmesõnad on [service],[year],[month],[day],[personalcode],[timeofday],[ms],[type]. Kohustuslikud pole [personalcode] ja [service]. Ülejäänud aga küll et tagada faili unikaalsus. |
temporaryStoragePath | Valikuline, kui ei ole määratud kasutatakse võtme storagePath väärtust. Hetkel kasutatakse manuste mahasalvestamise puhul. (commit:b918b8805c23) |
| kui väärtuseks on :inmemory: siis vastu võetud manuseid käsitletakse vaid mälus. (commit:c18fc1ae37b0 (1.0.6.4) ) |
Konfiguratsiooni saab hõlpsasti muuta ka koodi kaudu, tavaliselt võib olla näiteks isikukood muutuv vastaval kasutajale:
static void Main(string[] args)
{
var client = new CalcAdapter();
client.XteeCommand.Configuration.UserId= "12345678912";
}
Päringu "Interceptorid"
Alates versioonist 1.0.5.1 on võimalik dekoreerida päringut nn. "interceptor"-itega millega
on võimalik rikastada funktsionaalselt päringu käivitamist. Selleks tuleb klient süsteemis implementeerida :
public interface ICommandInterceptor
{
/// <summary>
/// Called before request is sent out
/// </summary>
void Begin(ISoapEnvelope requestEnvelope);
/// <summary>
/// Called after execution completes either with failure(exception not null) or successfully (exception null)
/// </summary>
void End(ISoapEnvelope requestEnvelope, SoapEnvelope responseEnvelope, AboutCommand aboutCommand, Exception exception = null);
}
Seejärel see registreerida järgevalt:
(näide PaintShop projektist mis logib päringu info konsooli)
var adapter = new ColorsAdapter();
//Examples\PaintShop\Client\CommandLoggingInterceptor.cs
adapter.XteeCommand.Add(new CommandLoggingInterceptor());
Alates versioonist 2.0.1.3 on võimalik dekoreerida päringud ka teenusepakkuja poole peal.
Selleks tuleb teenusepakkuja projektis luua klass, mis implementeerib ICommandInterceptor ja
kirjeldada see configus elemendi adapter.configuration attribuudis commandInterceptor.
<adapter.configuration commandInterceptor="MyNamespace.MyCommandInterceptor, MyAssembly">
Serverrakenduse ehitamine
Generaatori kasutamine
Esmalt on vaja genereerida struktuurid ja kompileerida teeki samamoodi nagu eespool kirjeldatud.
Serverrakenduse ülesseadmine
Klientide teenindamiseks tuleb koostada teenuse klass, panna pärinema soovitud teenuse interface-ist, mis on kättesaadav geneeritud teegist (geneeritakse wsdlist operatsioonidele vastavad interface-id) ja implementeerida ProcessRequest meetod:
namespace Server.Services
{
public class ServiceMultiply : MultiplyServiceHandler
{
public MultiplyResponse ProcessRequest(MultiplyRequest input, MultiplyInputHeader header)
{
return new MultiplyResponse(input.Request, new Result(input.Request.VarX * input.Request.VarY));
}
}
}
Selleks et teenus ka tööle hakkaks, tuleb konfigureerida rakendus:
Registreerida sektsioon konfiguratsiooni failis:
<configSections>
<section name="adapter.configuration" type="Xtee.Core.Adapter.Service.Config.AdapterServiceConfigurationSection, Xtee.Core"/>
</configSections>
Ja konfiguratsioon ise:
<adapter.configuration storagePath="stored_messages" storeMessages="true">
<services>
<clear/>
<!--Xtee operatsioonid seotakse konkreetse klassiga mis teenendab konkreetset xtee
operatsiooniga -->
<add objectType="SERVICE" xRoadInstance="EE" memberClass="GOV" memberCode="700030" subSystemCode="Calc" serviceCode="Add" version="v1" servicehandler="Server.Services.ServiceAdd,Server"/>
<add objectType="SERVICE" xRoadInstance="EE" memberClass="GOV" memberCode="700030" subSystemCode="Calc" serviceCode="Multiply" version="v1" servicehandler="Server.Services.ServiceMultiply,Server"/>
<add objectType="SERVICE" xRoadInstance="EE" memberClass="GOV" memberCode="700030" subSystemCode="Calc" serviceCode="Subtract" version="v1" servicehandler="Server.Services.ServiceSubtract,Server"/>
</services>
<xteeTypeAssemblies>
<clear/>
<add assemblyName="GenereeritudDtoDllNimi"/>
<add assemblyName="GenereeritudSerialiseerijadDllNimi"/>
</xteeTypeAssemblies>
</adapter.configuration>
Xtee serveri konfiguratsiooni (adapter.configuration) võimalikud atribuudid on:
atribuut | väärtus |
commandInterceptor | Täispikk klassi nimi, mis implenteerib ICommandInterceptor ja komaga eraldatud dll nimetus, milles vastav klass asub. |
storeMessages | (true/false) Kas sõnumid salvestada või mitte (vaikimisi:false) |
storagePath | asukoht kuhu sõnumid salvestada, võib olla nii relatiivne kui absoluutne rakenduse suhtest |
message-path-format | Võimaldab kohandada salvestatavate sõnumite asukohta võtmesõnade abil. |
| Vaikeväärtus on: [service]\[year]\[month]\[day]\[personalcode]\[year]-[month]-[day]__[timeofday]__[ms]@[client].[type].txt mille puhul faili asukohaks määratakse näiteks : ...colors.mix.v1\2013\10\23\38210272737\2013-10-23__21-04-22__012847@127.0.0.1.request.txt. Võimalikud võtmesõnad on [client] ,[service],[year],[month],[day],[personalcode],[timeofday],[ms],[type]. Kohustuslikud pole [personalcode] ja [service]. Ülejäänud aga küll et tagada faili unikaalsus. [client] markeerib päringu saaja ip-d, [personalcode] kliendi isikukoodi ,[type] - on tegemist päringuga või vastusega |
temporaryStoragePath | Valikuline, kui ei ole määratud kasutatakse võtme storagePath väärtust. Hetkel kasutatakse manuste mahasalvestamise puhul. (commit:b918b8805c23) |
| kui väärtuseks on :inmemory: siis vastu võetud manuseid käsitletakse vaid mälus. (commit:c18fc1ae37b0 (1.0.6.4)) |
Lisaks tuleb regisreerida teenuse httphandler:
<system.web>
<httpHandlers>
<add verb="*" path="AdapterXtee.asmx" type="Xtee.Core.Adapter.XteeServiceHandlerFactory"/>
</httpHandlers>
.........
</system.web>
Httphandleri-i registreerimine IIS7-es käib natukene teistmoodi, näites tooduna töötab IIS6-es ja ASP.NET development serveris .
Failide saatmisest .
Antud lahendus võimaldab saata ja vastuvõtta faile MIME formaadis. Lähtekoodis on ka näiterakendus failide saatmisest ja vastuvõtmisest: Examples\DocumentRepository.
Kui wsdlis on manused kirjeldatud vastavavalt xtee spetsifikatsioonile:
<complexType name="Document">
<sequence>
<element name="Name" type="string"></element>
<element name="Sisu" nillable="true" type="base64Binary" xmime:expectedContentTypes="application/octetstream"/>
</sequence>
</complexType>
või
<complexType name="Document">
<sequence>
<element name="Name" type="string"></element>
<element name="Sisu" nillable="true" type="ref:swaRef"/>
</sequence>
</complexType>
Sellisel juhul geneeritakse dto, mille küljest saab faili mugavalt kätte:
public interface IDocument {
string Name {
get;
set;
}
global::Xtee.Core.MultipartFile Sisu {
get;
set;
}
}
mis võimaldab saata faile otse failisüsteemist (endist viisi) või siis otse mälust:
FileInfo fileInfo =new FileInfo(@"/somepicture.jpg");
//vanaviisi
doc.AddDocument(new Document("docA", fileInfo));
//uuemat moodi
doc.AddDocument(new Document("docA", MultipartFile.Create(fileInfo)));
byte[] fileBytes = File.ReadAllBytes(@"/somepicture.jpg");
//baidid mälust
doc.AddDocument(new Document("docB", MultipartFile.Create(fileBytes)));
//vastuvõtmisel kui ei ole konfis :inmemory:
//siis toimib endiselt
var fail = document.Sisu.FullName;
// kui :inmemory: siis 'FullName' annab vea kuna fail istub mälus
//mõlemal juhul küll aga toimib
var bytes = document.Sisu.AllBytes()