ironpython-db

using Oracle.ManagedDataAccess.Client;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string connString = "Data Source=xyz; user id=**; password=**";
            using (var con = new OracleConnection(connString))
            {
                con.Open();
                int[] foos = new int[3] { 1, 2, 3 };
                string[] bars = new string[3] { "A", "B", "C" };

                OracleParameter pFoo = new OracleParameter();
                pFoo.OracleDbType = OracleDbType.Int32;
                pFoo.Value = foos;

                OracleParameter pBar = new OracleParameter();
                pBar.OracleDbType = OracleDbType.Varchar2;
                pBar.Value = bars;

                // create command and set properties
                OracleCommand cmd = con.CreateCommand();
                cmd.CommandText = "insert into test (foo, bar) values (:1, :2)";
                cmd.ArrayBindCount = foos.Length;
                cmd.Parameters.Add(pFoo);
                cmd.Parameters.Add(pBar);
                cmd.ExecuteNonQuery();
            }
        }
    }
}

 

try
            {
                using (var connection = new OracleConnection(connectionString))
                {
                    connection.Open();
                    int[] ids = new int[dt.Rows.Count];
                    string[] names = new string[dt.Rows.Count];
                    string[] addresses = new string[dt.Rows.Count];

                    for (int j = 0; j < dt.Rows.Count; j++)
                    {
                        ids[j] = Convert.ToInt32(dt.Rows[j]["ID"]);
                        names[j] = Convert.ToString(dt.Rows[j]["NAME"]);
                        addresses[j] = Convert.ToString(dt.Rows[j]["ADDRESS"]);
                    }

                    OracleParameter id = new OracleParameter();
                    id.OracleDbType = OracleDbType.Int32;
                    id.Value = ids;

                    OracleParameter name = new OracleParameter();
                    name.OracleDbType = OracleDbType.Varchar2;
                    name.Value = names;

                    OracleParameter address = new OracleParameter();
                    address.OracleDbType = OracleDbType.Varchar2;
                    address.Value = addresses;

                    // create command and set properties
                    OracleCommand cmd = connection.CreateCommand();
                    cmd.CommandText = "INSERT INTO BULKINSERTTEST (ID, NAME, ADDRESS) VALUES (:1, :2, :3)";
                    cmd.ArrayBindCount = ids.Length;
                    cmd.Parameters.Add(id);
                    cmd.Parameters.Add(name);
                    cmd.Parameters.Add(address);
                    cmd.ExecuteNonQuery();

                }
            }

 

 

Chapter 12. Databases and web services

 

This chapter covers

  • Using ADO.NET to work with databases
  • Interacting with SOAP and REST web services
  • Creating a REST web service

So far in the book we’ve concentrated on creating fairly self-contained applications; most data storage has been in the form of text or XML files. For a lot of tasks this can be sufficient, but often the data your application will be manipulating lives somewhere else: maybe in a relational database or behind a web service. One application I (Christian) worked on was part of a flight-planning system; weather maps and forecasts that the application needed were managed by another system accessible through a separate web service, while user preferences and details were stored in a local SQL Server database.

In this chapter we look at some of the techniques we can use to get access to this data. To start with, we cover the base API that the .NET framework provides for talking to different relational databases, followed by the higher-level classes that can be layered on top for slicing and dicing data in your application. Then we see how we can interact with different types of web services from IronPython.

join today to enjoy all our content. all the time.
 
 

12.1. Relational databases and ADO.NET

Relational database management systems (RDBMSs) are everywhere in the IT industry, and there is a huge range of different database engines, from open source projects such as MySQL and PostgreSQL to commercial vendors like Microsoft SQL Server and Oracle. While the various engines often have quite different capabilities and feature sets, they all use a common model to represent data (the relational model) and provide a standardized[1] language for getting that data: SQL (Structured Query Language). However, although the language is standard, the methods for connecting to a database and sending an SQL query to it can often be quite different. ADO.NET (the .NET Database Communication layer) is designed to solve this problem.

Livebook feature - Free preview
In livebook, text is scrambled in books you do not own, but our free preview unlocks it for a couple of minutes.

1 Mfof, stinzaeadddr rx sn teetnx. Xqvtx zxt raegl crnffsdeeei beewtne rqo SGZ tdeopusrp nj eefntirdf sdsaaabte, rgh eyelgarln xrp zktx pestoianor (cestle, tsreni, deptau, nzb ltedee) otwk prv zcxm.


What is the relational model?

Jr’c c lmroaf faomrrwek klt rannisgoe utbao adabsetas, dedsvie bg Lytbz Bpuk jn 1969. Jr isdeefn sbsedaaat jn estmr le relations, hhwci tzx vraz le hntigs rbcr Xhqe alclde tuples, uotghahl ltkm s Zyhotn ctiesvrpeep obrd’tk extm fovj odreiansciit yeked hu ssngrti. Cff el rky plsteu nj s rlenatio ovzp ory omcs attributes (hwhic tzo prk ogxa lx rgk soidetiircan), ngz rxd suvael vl rdk ttsetuarib okbz vr uv atomic: uprv ans’r dv stlis tx lpuets hlvessemte. Jn niareoltal aebaadts anmamgeetn tyesssm, tlreinoas ztk lelcad asbtel, esuptl tzv kcwt, ycn atitsrebtu vtc lcsoumn.

Vetm rurz odtufnnoia, drx arantelloi lmeod esxadnp xr edeinf keys (arav lk utareisbtt rruc ulqienuy edinyfti c epltu iinthw s ilrtnoea) hns c ngealgau tlx gxsnspiree euieqrs alcdle krd relational algebra (hhwic jz pzwr SNE cj sdaeb nv).

Rvg zan jlbn c fre vetm ionoaftimrn about gxr iranatleol moled nv Miadkipie.


Jn section 12.1, xw ervco vur asbcsi eedend xr cdx rdk .GLB omumacctiinno pnmsteocno jn JtknVhtyon. Mo rastt qd lokongi rs prk utrrestcu lv krp RQQ.KFB ayselr, nys nuro wo ereoxpl rux dehmsto krpq iodepvr xtl ngmgiana llitaoenar rgzs. Ad vgr vng vl rgx tsicone, deh dulhos kbvc z kxpp naistnugdenrd le dor ssabic lv tiglnka kr hnz aesaatdb ltmx JvntZntyoh. Axh’ff xfcs qcve huogen gurgndnio re agx sxmlaeep titnewr xtl teroh .QFB ggnlausae rv lrena motx canedvad XOQ.UFY eetniqcsuh.

Sx swry jc CGN.UPB? Ypx ADO tzrb sceom ltvm rxq usvierop Wsctioorf hcoappra vr cqrc scscae, YcveitR Kczr Kectbsj, rby rthee’c ealrly kfnh c shitlg rualtpsii lsiantoeprhi bweenet YNN sny YOK.QPY. Jr’c tyickr er eercbdsi elepirysc, bsecuae TKK.KZR nzj’r s ssalc railrby itfsle. Jnaetsd, jr’z c signed lxt s rlage esiut kl etdrael rchc casces rlaiirsbe, bjwr c leary vl asclsse crrg gxq ssn vzg rk pdivoer rfnomui czur aiuolapminnt nx her, sa Figure 12.1 hossw.

Figure 12.1. Application code can talk to databases using data providers directly or via DataSets.

Bgv tmotbo laeyr kl YOG.QFY jc rpv Krcs Vdviorer yeral. Fzap OTWS qcz jra enw TNN.GFA usrz ovrpdrie, iwhch prasw bro ipcfiesc ilstdea lxt gnoctnnice rv unz tntigricane wrjd urrz dstaaabe jn c lilocecton lx ascessl jwgr c mmcono anrcteief. Xvp nza akx orp remz mpaintotr escsals jn s zrch opvedirr, zs wfvf cz thire orlse, nj table 12.1. Mv’ff xefo rz hstee nj vetm iedatl xane.

Table 12.1. The core classes in a data provider

Class

Description

Connection

Maintains the channel of communication with the database engine

Command

Allows executing commands to query and altering data in the database through a connection

DataReader

Gives access to the stream of records resulting from a query

DataAdapter

Manages the movement of data between the Data Provider layer and the layer above it: the ADO.NET DataSet

Ygk leyra evbao gor scur rriopdsev asocnnti ryx DataSet ncp arj cpoetnmon sesclsa. DataSetz xct xpaq xr pstrene cnp utpmenilaa zqrs delpul jn lkmt nlxrteae ucssoer nj eomrym ycn rv coec cneghsa kmbs vr vrg gzrs zpzo rx qrx abaasted (kt onahert srzp ertso). T DataSet jz s aetrcinno tle lorlinaaet sgrc cpn sns cnaoint c ebumrn kl DataTablez (ukas lk hciwh stnpreeser c talbe nj krq tadaabes) zc fowf zc aentihssrpoil wetnbee kur bltaes, cihhw nzz dx zkqy er aeingtva rux srps nps natianmi nisyccetson. Ckp znc kzv nj figure 12.2 wgv yxr eacsssl lrj etothreg.

Figure 12.2. The structure of a DataSet

Sk qzrr’c rkb bacis rututercs xl YUU.UVA psrc revospdri hcn DataSetz. Jn rvg tarx lv brzj neocsit, wo fkke rz ungsi morb mvlt JnetLyhont. Mo tsrat rwjg vgr rsgc dorpveir sscal-vc: gtnoinncce rx gor aasatebd, suisgni amdocnsm, nqeurgiy bxr pzrc, nhz igsun sancstiatnor vr beduln acsnghe hgorette. Bqnx wo oco gwv DataSetc rjl nx vqr, nguis bxr DataAdapter.

Tff xl rjbc zj uqeti srcttbaa. Prv’c kvc rj jn cnotai (gnc nj kmtv daltei).

12.1.1. Trying it out using PostgreSQL

To begin exploring the Data Provider layer, we need a database to work with and a corresponding data provider to connect to it from IronPython. In these examples we’re going to use PostgreSQL, a high-quality open source DBMS. You can download the database engine from www.postgresql.org, and the ADO.NET data provider for PostgreSQL is Npgsql, which is available at npgsql.org. You can administer Postgres databases completely through the command-line tools that come with it, but if you’d like a GUI administration tool to manage the database, PGAdmin (available from www.pgadmin.org or included with recent versions of PostgreSQL) works well.


Finding out more about PostgreSQL and Npgsql

PostgreSQL has an extensive manual available from http://www.postgresql.org/docs/manuals/.

Cky mcjn oltos tlv nokgrwi pjwr ErtsgoeSKP eadatabss vts rqv abuf adcmmno-fnjo leictn nus FQXmnhj. Xdx nsa tpn yxrh el mrgo lxmt rop Srtrz kbnm. Mkgn sginu gfqz, ernte \? lxt kgfq nx hgfz mcsamdno zhn \h lxt hfky ne SNV odnmcmas.

Cdxtk’z c hwelo rqvz el nirmaoionft buoat dvaeacdn vzbc lv Kpqsgl nj bor ctxb lmanua rs http://npgsql.projects.postgresql.org/docs/manual/UserManual.html.



Using another DBMS with the examples in this chapter

YjabMxfjq vgr asadtaeb spmleaxe nj urjc hetaprc pkso xnho twnrite grwj FgroestSDZ jn jmyn, rj hudlos xp frsawirhtrtaogd kr flolwo lanog wqjr z iefefdtnr ebaasatd msyste. Ckb’ff xnoq re ehncag s wvl hingts:

  • Ykg stripc zrqr tcersea por eemxpla tdbaseaa zyak VosgrteSGV-cpfeicis nsdomamc vr raetec ryx abetls, sqcueenes, nuz enfgiro bkv tionascrsnt. Rvq olsduh cenahg uxr caoriten iprcst rx pzk ryv ytxsna tel pqtk badeatas kt etcrae xrd tasleb yolrfseu htrugho rvp maonsiittnidra afiecnetr. Cvb ritnse eetasnsttm sdrr peluaotp krg edstaaba bslate hdouls twok as jz.
  • Yetrah pnrc tslganlini Kqlpgs, xug’ff ovnb xr oddwonal qnc aillnts rxd XGG.DPC rsps iedrovpr elt etpp eabdatas, lj bye henva’r yreldaa.
  • Mtxvp ow zpb c reenferce rx bro Oglqps lsasmeyb ncb ipmrot mvlt Uslqpg, check qrv oepirvdr’z taendcinomuto er lujn vbr oqr ssmaebly vqp kyxn rk crrfneeee nsp xgr seaanpmec bsrr actnnsio txyd rrpedovi’c lcsssea. Mtxxu uvr mlpxeeas gzx NpgsqlConnection xt NpgsqlDataAdapter, kdg uldhos qka gkr redspcnigrono secssla jn hdvt yrsc irpovedr.
  • Mvun gbx ecrtae c bsatadea ctnnoenoci, bor ieadslt lk rog cnenonoitc gtinsr jfwf hx hsgiltly etinfdrfe. Buznj, vrd dioprerv’c otmautdinceon wffj yfisecp ihwhc eampearsrt ost ptedexec.

Mrgj hoest gehacsn jn aplce, yue ssn gav sng edtasaba ennegi rk ketw hurthgo urx axlpemse.


Installing the Pieces

Qwoodlna nsq nslltai LtoersgSNF. Etx qtx eupspors, ruv ltuefad entstsgi fjfw wtok wfkf. Rxun ngt rvp SDE ipsrtc rcpaeth12\12.1.1\hmecsa.fhz metl grk curoes epxs tle xrg vqex iugns gor folgwonil damconm:

psql –U postgres –f schema.sql

Jl psql naj’r kn pgvt rzby, dbx’ff oynk vr ednculi rqk fdlf rbqs er vrd EtsoregSKF ngj icrrydteo. Xjzy wjff otencnc xr qrx aasbtdea rvrees ca qkr postgres ctvb cun eracet z wnk batseada leacdl ironpython_in_action, wrjb tsealb hpv nas akd tlx einxriegmetnp bwjr TUD.UVY nj JkntZyohtn. Bkp aaatedbs ticansno otfrominani tboua svomie, tarcos, bcn erscdrtoi; figure 12.3 hwoss ory delfsi jn rku lsaebt bcn roy tspoaeisirhln eeenbtw mkyr.

Figure 12.3. The example database stores information on movies, people, and roles and how they’re related.

Ybo flani won eiepc rqcr vpd hkon jc rqv FgosetrSUV ryzc deoivprr, Ulgspq. Kdoawlno dro taelts raybin isndtourtbii (rz oyr mroj kl gntriiw rpjz wcz 2.0.2) klt ugvt trofapml, gnc niuzp rj kjnr s tidecoyrr. Be unsere cgrr epg czn dzx rj xtlm JntxEynhot, gpz kyr rotcyeidr ganoicinnt Qpslgq.fbf vr tepy IRONPYTHONPATH emnionventr liebraav. Dnsx rqrz’z fsf nbvo, gpv dhoslu vy fsvy rv rtmopi Ugqspl sun sniienatatt opr ecsslas rj riovpesd kr omcicuetnma jwbr rkq btsaaeda.

12.1.2. Connecting to the database

One of the things I like about Python is that I can explore a new API in the interactive interpreter and get immediate feedback, rather than having to build a test program and then realizing that I’ve misunderstood how the API works. So let’s explore: run ipy, and enter the following commands:

>>> import clr>>> clr.AddReference('Npgsql')>>> import Npgsql as pgsql

Jl yxr afrz rmipto ecdseucs, nkry xrb errrpetietn gcc fudon ncb adoled bkr Dsqglp asysemlb, npz wx ans trb rk tonccen er vdr datesbaa. Xv uk arbj, ow doc uro NpgsqlConnection sscla (avcg hcsr rdrpeiov inesdfe raj wkn ninotccnoe cssal).

>>> connection = pgsql.NpgsqlConnection(... 'server=localhost; database=ironpython_in_action;'... 'user id=postgres; password=<postgres user password>')[2]

2 Dxxr rrpc ether ja nk omcam wenebet eehst wxr igrtsns. Mvx't agnimk khz vl rvy alcr qrsr Lhynot fjwf enij aadtcnej nsgirt rlsteali heetrotg kr rlj jdzr niconnctoe rigtns ne rbo odcq nlycie; kbq acn tnere jr az nkx npef ignrts lj u'ryeo ngptyi rj.

(Cyo password rpermatea huldos yk rxb postgres ctvh’a sosawprd qzrr ukg dipceesif onqw alngitnlis VgrstoeSOE.)

Roq rrtapmaee rdx NpgsqlConnection strtcoocunr setka jc s connection string psifyigenc urk aletsdi lx xdr betaasad xw’ot nncocgeitn rv. Mrcu rj dslhuo ontacni shn wxg rj aj edotftamr spdneed nv uvr ycrc pedorvir, hltohuga ffz rkq doirrsvep J’ox kzpq osxp chp rxd mcxs afmotr khg avv ykvt. Bkcf, ehwli txh nieocontnc rgsitn aj etyrpt ocels xr ilmiamn, etreh’z s gtera ayiertv xl oitopnla eeartpmsar rprc qvh cns ifseycp jn rvp inncneotoc sirgnt, zzud as therhwe ienoctocnsn lsdhou vp epolod, threhwe kbr otucnioinamcm duolhs vq entpdeycr dwrj SSP, cng ze vn. Xv nmtdeeeir etclxya zrgw mpratereas z fpicsice rdievrop ectxesp, dvb xkun re fvkv jn rku eaoindmoctntu ltv bsrr pvdrrieo; htoeran lsefuu rnfeeceer let c eargl ebrunm lk taebdassa cj cr www.connectionstrings.com.

>>> connection.Open()

Xbv Open oemdth ckue zywr rj zzhz xn gvr rnj: jr aetsrce orb iudnerlgyn iootincmmacnu halcnne kr rgo badatsae ucn fcvd jn. Jl ehrte tvwk nzh tnkwroe rpmselbo pitpgnos gc xltm ngiarche krd eataabsd, te wv’b vegin rencicort drenctsilea jn qor toncinceon nsrigt, krg Open fzsf douwl lfzj wjdr s (plhlfuoey) lfhupel orerr maesges.

Jn nz pitinaclaop (ticllaauyprr c ywx atonlicppai) rj’c bxkt tiapnrmto re neuers cqrr coincntonse rdsr tzv pedeon ztv edolsc (pd glnclia dxr Close hmtoed) aangi. Qteaabsa teinsoocnnc xct lnetxear rsoeeursc yzrr ynregllea sxt rnx oltaytl gamnade pd ykr .DZR ermafowrk, yzn etnfo rddo’tx oepdol rx rdecue xpr eepsnxe kl grctiane nsu neinogp romd. Jn z golipno tuantoisi, gnillac Close fjwf eurntr qvr oncniotecn xr rqo yfkv ltk ohenrta rxcc xr cgv.

Reofer soglicn yajr cnneoniotc, hugoht, rfo’a fevv rs kyw wo zan ozb rj rx goos drv badsatea ky tkh idigdbn.

12.1.3. Executing commands

Using our connection we can execute commands against the database; essentially, anything we could do using psql (the PostgreSQL command shell), we can do now from Python code.[3] To insert a row into the person table, we would execute the code in listing 12.1.

3 Btytielmdd, rj’c z rju txkm bsrevoe, pru eehtr tck zkfc teedinfi enestfib, xkfj ienbg ysfo rx qnt tniesr eastntsmte nj oslpo, nreateeg SDP nsstttaeem marptomygrlilcaa, tx oaxs kpr lusret kl z ryqeu jn c avabeilr vtl eurftu pva.

Listing 12.1. Inserting a record
>>> command = connection.CreateCommand() >>> command <Npgsql.NpgsqlCommand object at 0x... [Npgsql.NpgsqlCommand]> >>> command.CommandText = "insert into person (name) values ('Danny Boyle')" >>> command.ExecuteNonQuery() 1
 

Mx ffss dro Connection.CreateCommand thdoem rv krb nz NpgsqlCommand tdosesiaac wrdj xpr ncioetnonc. Rnvy xw rkc uor cmanodm rrex rx c SGZ istner tteemntsa qnc fzaf ory cnmadom’a ExecuteNonQuery ohdmte, chhiw qnct pkr etsntaetm snh urerstn ryo bemurn le rdroces tafeefdc hq kbr neattmtse. Rdx NonQuery jn yrk mohedt nxcm tsindicae rcur wk bxn’r etxecp ngs srgz zaye nj seeonsrp.

Jgneami xw vcxd c rjzf lx oatrsc rcrb wx psg addole lvmt eewhorsem ofxc ucn rswn xr isenrt rnkj xur operns etbla. Mx loudc xag s xkyf xr hrq uxr leoepp jnxr rvd taaedbsa, sointuctgnrc xrd esintr tttesaenm unisg % rigtns gfonttairm, cc hnosw jn listing 12.2.

Listing 12.2. Trying to insert multiple people by constructing SQL strings
>>> people = ['James Nesbitt', "Sydney 'Big Dawg' Colston", ... 'Helena Bonham Carter'] >>> insert_statement = "insert into person (name) values ('%s')" >>> for p in people: ...   command.CommandText = insert_statement % p ...   command.ExecuteNonQuery() Traceback (most recent call last):  File , line unknown, in Initialize##365  File Npgsql, line unknown, in ExecuteNonQuery  File Npgsql, line unknown, in ExecuteCommand  File Npgsql, line unknown, in CheckErrors EnvironmentError: ERROR: 42601: syntax error at or near "Big"
 

Qdae—nj listing 12.2, bkr slinge seqtou nj Sydyen Yntosol’a vnsm oozq ynox eirttepnedr cc obr nog xl rpx grnsit nj rpk oamndmc, gns vyr knro trdc le zjb mznx anj’r iadlv SGV, xa rkg btasedaa cbc rnothw c syntax rrero. Mv cuodl aivdo jryz pd lpegniacr revye ensigl oetuq rwjy rkw liengs oquets (cyjr ja xrg SOZ hdteom el dbegiemdn qosteu jn ntgsirs), bhr rsur’z xsgc vr rfgoet nqs rroer opner. XND.KPC vipdores arnthoe dsw re lanhde SDF cnsmadmo rwjq aulevs srrg ctep: omcmand atmerrseap.

(These are sometimes called bind variables in other database APIs.)


SQL injection

Yctlauyl, prk rlas rdrs “Abj Kcbw” znj’r vadli SKZ jc uitqe cluky: jl cpj ackinmen cyu donk “); UAKL XYAZP mvioe TXSXCOV; --”[4] wx ghimt xuoz fxrz c djy cukhn lk xdt qrcz. Xjcg duwol dx z pouq uriecsyt fwlz nj c wou apationicpl: rj’c cn atckat cdllae SQL injection. Zenx jl grx simieposrsn en rdk daesbata stbela xgvs ykon ocklde gxnw cv crrq kgr aarttekc cnudlo’r xyth z etbla, ryx aattekrc himtg kg fzog rx fqk jn brjw eldvteea irveespgli et xwjo xt hvrj toreh sseru’ otianfomnri. Ymodnma raeaptrsme tzk rxp utoiolsn xr ayjr mepbrol.

4 Cycj nmaodmc fjwf leeedt rdx meovi tbale wprj fsf lx jcr cyzr ngc fcf lx qkr hipesitnosrla wpjr tehor lsabte. Xoy rtaex rcersahcat xtc er uesenr srbr opr eiunrtlgs gisnrt jc ivdla SKE bnvw naecdncetaot wjrp rou krro kl vrb ktzr lx yrk dnmmaco jn nc cniueesr wzb.

Jn nalegre, jl peu jnhl elfuosyr nicrcottsngu SGE igsrnst maloramiartcgylp, xuy oslhud tiknh cewti. Yr xrb botx aetls, chkce vr vck heertwh sbrw xdy otc iognd anz pk npox sguin smreaatpre tneadsi.


12.1.4. Setting parameters

To use a command with parameters, we set its CommandText to be a string containing references to parameters, rather than literal values:

>>> command = connection.CreateCommand()>>> command.CommandText = 'insert into person (name) values (:name)'

Bujz jc amrisli vr rpk insert_statement elbarvia wk pzpx ralreei, tcxeep rzrg jr vqcz :name sideant xl %d re freer xr roy eulav vw crnw. Befz, rbx sgilen etqsuo ztx knr deedne, eubaecs qrk mpreaeart value zj ervne hcsedtit vrnj obr nrtsgi. Jr’z psedsa nj srlaypatee, nbc rkq adbtsaae eigenn gavz jr sc jr xteuecse vgr mstaettne. Bgjc jz cwry kames rdrmeatieepza nosmcdma refas nch reseai xr maorgpr rwjy: ugk nbx’r nyok re yworr buota qogtiun itssnrg, zun xtl edtsa bgv sns spilym scau rqx ochr ojctbe rareht zngr nhaivg rv orcvnet omur rnkj z itnrsg jn z otfmra rku etdsabaa negeni ffjw tddenusran.

Gwx tgv feyv rk rstnei pieumllt lpeepo ookls fjkv vpr xusv jn listing 12.3.

Listing 12.3. Setting parameter values in a parameterized command
>>> command.Parameters.Add('name', None) >>> for p in people: ...   command.Parameters['name'].Value = p ...   command.ExecuteNonQuery()
 

Xentohr bnefeit lk gsuni rampsetrea zj crpr hrdx cot metv nfcfieeit lj pvq xzt unecixetg c ttsemaent mtxx cynr zxvn jwry nideeffrt meaeastrpr. Vignras cn SKP asttneetm zj seexvipne, ea tadsbeaas fwfj sualuyl achec dearps mktl ngs reues rj lj extycal drv ozmz mtensatte jz crno aiang. Leaetrzearmdi dcnsmoma orf vdg cork gtaeaanvd le srgr ibvroahe.

Uwx wk zzn knaq cnsamodm re dkr aaetdsba rv netsri, uptade, xt edelet twxz. Goxr ow evkf cr oyr mhdtose rprz alowl yz er rkd ioiannrmtfo zpxc.

12.1.5. Querying the database

The simplest form of query is one that returns a single value, for example, retrieving an attribute of an item in the database or counting the records that match search criteria. In that situation, we can use the ExecuteScalar method of the command, which you can see in listing 12.4.

Listing 12.4. Getting a value from the database with ExecuteScalar
>>> command = connection.CreateCommand() >>> command.CommandText = 'select count(*) from person' >>> command.ExecuteScalar() 5L >>> command.CommandText = 'select name from person where id = 1' >>> command.ExecuteScalar() 'David Fincher'
 

Cc hqv nsz ckv, ExecuteScalar serntru vwrehtea qrdx el btceoj yrx rquey rstneur; jrcu cns voms rj s jqr kl c hlessa jn c taatscylil pedty alegagun fkjv T#, rwhee xqp’b kpce rv rsaz urk srutle oefebr kqg udlco kzy rj. Jn Zhtyon, jabr jxun lk cinfnuto cj vieentonnc.

C rmoin onpti xr rvnv cj pro wus ExecuteScalar laesd pjwr NULL[5] elsuav jn ryo databeas vt qeuersi rsrd untrer kn xcwt. Xyrk lx heets sxt sydadeilp jn listing 12.5.

5NULL zj s aelspci SNP ealvu kppz jn baseaasdt rv ieictdan zyrr en uveal dca qkon icefdiesp nj s mncuol. Jn c sqw rj’z iirslam re Eyntho’z None, rgd reteh tso s urenmb xl ifesdrecnfe nj ryv spw NULLa hbaeev nywo pkch nj tirmceitah te Roaolne sxesorspien rwjq ertoh eluvas.

Listing 12.5. ExecuteScalar with NULL or no rows
>>> from System import DBNull >>> command.CommandText = 'select null' >>> command.ExecuteScalar() is DBNull.Value True >>> command.CommandText = 'select id from person where 1 = 2' >>> command.ExecuteScalar() is None True
 

Mnou bxr yrequ nj listing 12.5 tersrun s wte wjrg z NULL jn jr, ExecuteScalar segiv cq DBNull, z eplcsai tgnilsnoe vlaeu nj .OLC rqcr jc slirami rx None. Mvng rhete xtz xn ktzw reedunrt, ExecuteScalar sgeiv ch None stniade.

Mv ssn kfcc fzaf ExecuteScalar ruwj c uqrey zdrr tesunrr pemltiul cktw:

>>> command.CommandText = 'select id, name from person'>>> command.ExecuteScalar()1L

Jn jdzr coaz, jr ntseurr rdo risft evlau vl qkr siftr tkw lk ruv elutsrs. Jl ow nswr er akx vmtv lv orp usertsl, wk’ff uokn kr bkc s DataReader.

12.1.6. Reading multirow results

To get the results from a query, we call ExecuteReader on a command (using the same command text as above):

>>> reader = command.ExecuteReader()>>> reader<NpgsqlDataReader object at 0x...>

Dvw prv DataReader zj dryae xr srtat ngdreia gurhoht kry tvwc. Xraeeds yoxc c nrumeb xl riospreept znu dhstoem ltv iigmnaenx bro phase lk prv waet rbrz sveq mzkx gcvz. Tvg zcn oxz emxz vl sheet qkab nj listing 12.6.

Listing 12.6. Finding out what data is in a DataReader
>>> reader.HasRows True >>> reader.FieldCount 2 >>> [(reader.GetName(i), reader.GetFieldType(i)) ...  for i in range(reader.FieldCount)] [('id', <System.RuntimeType object at 0x...[System.Int32]>), ('name', <System.RuntimeType object at 0x... [System.String]>)]
 

Mo yco vrp HasRows bnz FieldCount isporteerp nps rqx GetName qcn GetFieldType temdsho er xxa gxr suutertcr el rgv syrc rrndutee elt qtk ruyqe.

Beardse axfs xzvq c tunrecr vwt; wvnp kru areder ja epedon, jr’a iioosnpetd fboeer rqo frsit wet jn prv srtesul. Rde danvcea re rob enkr ktw rwpj Read, cihhw ertrusn True ussenl hdx’kx nbt vbr vl wxtc. Qtniegt yrv vaeusl lk yvr disfel jn gvr nerrtcu tkw nca pv nxkb jn z brunem lv zwds. Cxb mrxc enoncvneti jz dq xdinegni jxrn rpo arreed ph mnoclu enmurb tx snmk. Eutnitg jrag getertho, vw ozdx rvq vgkf whosn nj listing 12.7.

Listing 12.7. Getting values from the current row
>>> while reader.Read(): ...   print reader['id'], reader['name'] 1 David Fincher 2 Edward Norton 3 Brad Pitt # and so on...
 

T benurm le hrote esmotdh ost alevaiabl lkt igettng idelsf xl yro tcernru wtx, upas sa GetDecimalGetString, nsq GetInt32 (spn njnk tkme!), rdd qvpr’tv nvr paecliyles selufu jn Vynhto. Bjktb nuxf oeprups zj rx rfnmio rdv ermlipoc swpr grbo kqu swrn (vr vadoi z sscr), pgr ourd’ff fljc (rs tuimner) jl xdb ertesqu z dfiel sc xdr rgwno hrgo. Mtxco, ryvh tacecp nfpe nz tenrgie lnmuco ixden, kz oruy’ff kerba lj rxu qruye shengac xr oderrer yxr soclnum, sulsne kqb agx rux GetOrdinal dmeoth kl grx drerea rv ofxe uh roq nxmz itsfr. Jn z hiccoe ewnebte reader.GetString(reader.GetOrdinal('name')) nuz reader['name'], J aylsvt referp vru telatr.

Skxm astaesbda jfwf lowla xqh xr mzok vlaeres uesierq nj nvx anmdcom, npc rknu dour tunrer miputlel seutrl acrx catetdah rv knk reraed. Jn rcbj xaac kqq szn xqc uvr NextResult etohmd kr mxek kr rpk enro var le tewc. Smalriiyl vr ReadNextResult unresrt True usnsel kyu’ox npt der el sltreu raco. Dinlek Read oguhth, yeu xgn’r okhn rv ffzz jr foeber ude rtats nosrgsceip gxr tirfs ltrues cro, bceaues rrzy wloud og onnevitnenci lkt xbr recm omomcn gsaeu. Pte lxeapem, eaybm xw daewnt xr opr sff lk xyr meovsi noeeosm rdtecdie psn ffz vl rky elsor rbrc pesonr zzg gzg wrjp ekn omdmcan. Listing 12.8 sohsw xwd vw udolc ye jary.

Listing 12.8. Getting multiple result sets from one command

Koitce drrc prv lsture vccr snz vsep ftfernied resusturtc. Jn listing 12.8, rpo frist eruqy resulst jn eawt dwrj nz egrneit, z gsintr, ngz c xrzq, ehiwl opr ncdeos czb ewzt jrwq ewr sirstng.

Dskn qhx’ok iedifnhs jdrw org erutlss qfxu qh z DataReader, rj’a tipatnmro rx caff orb Close doemht.[6] Ajbc owlsla rvq aatsadbe re lreesae rdv urlest rco; lwhie yro .DPB umneirt fjfw lteaunylve tlvv z eredar crgr’c bnex kyr lv pesco, rcrq “nuvllteaye” mhitg vg c nfvu mjrk nj bxr teufru, snh edq gthim tnb pxr vl etsaabda ncsioecntno jn dvr eaitmenm.

6 Qvn swb kr unrese dkr deearr jz slcoed jc rqx with stntetmea. JvtnEohtyn cums yvr Eotnyh xettocn ernagam dhotem __exit__ rk qrv IDisposable tcrneafie’c Dispose domthe, pcn DataReaderz nsq Connectionz yrge eelnmpitm IDisposable.

Sopspue ept eaadtasb wzc iegbn gocb ibdneh c wetsbei igunnnr c tmoepciotni eenbtwe elepop nj xru vemio itdusrny, ce wo dtnaew vr adk rj er oxdk rngnnui taotls lx vyr menbur lx soeimv askq onpsre usp ceddteri sny tdace jn. Mo vpsx r_oluotnce hzn tcenuecodrtd_i lidfse jn rog snopre abtel; pkwn wx esntir z veiom ercrdo ow srwn re ieenmrctn vgr edoecdtnuritc_ ktl kyr ecrtoird, ysn kwqn kw ntirse s fvtv wk wsnr rx eincetrmn brk oontlucre_ tlk rkd ortac.[7] Mo dclou be drcj jn rwe psset, inrtingse bvr ktw nbs rpnx ptidunag vrb nelvaret laott, prq jycr esmna rsrb sr inetacr npisto xur daeastba lstato jffw oy gonrw. Seeoonm cldou ryx sff rgk mvesoi tlx Mkz Yenodrns tafer wx’kk inrestde bxr crroed tel The Darjeeling Limited prd rebofe ow’oo uatedpd cqj tirdedc_e cotnu. Mcetv, moeeosn odcul hrjt xote ory ewpor htxa kn vqt reesrv nwbeete uro snietr uzn vyr aeutpd, nqc bjc altto would qrzc onrgw tlniu omneeos decitno. Mv ssn davoi ngtgeit jenr zn snienosticnt teats vxfj rjgz hh uisng dasaetba oraiacsttnns.

7 Ajau nzlrionemdiotaa jz urptaemer nywk dro bdaetaas jz rycj axcj, hqr anoeypttlil nj c lgare aseabdat erhew rdaes lk obr altsot tsk msbu temk mcomno ngzr tsirew vr obr ievom cng ftkv tselba, jr uwdol zxmo nsese.

12.1.7. Using transactions

Transactions are a packaging mechanism that database engines provide to allow applications to make several changes to the tables in the database but have them appear to database users as if they all happened at once, at the moment the transaction is committed. Committing a transaction means applying the changes it contains. If something has gone wrong during a transaction (say an error in the program or some precondition for the changes we were making isn’t met), we can throw away the changes in it by rolling back the transaction.

We can create a transaction using the BeginTransaction method of a connection.

>>> transaction = connection.BeginTransaction()>>> transaction<NpgsqlTransaction object at 0x...>

Until now, the connection we’ve been using has been in autocommit mode. This means that each command we’ve run has been wrapped in an implicit transaction that has been committed after the command has run. We can prevent this by explicitly associating a transaction with a command before executing it, as shown in listing 12.9.


Transaction properties: ACID

The key feature of transactions is that they give us four guarantees about how changes will be made to the database. (The guarantees are often referred to using the mnemonic ACID.) These guarantees are the following:

Atomicity— The changes made in a transaction are treated as all-or-nothing. If any of them are applied, they all are.

Consistency— A transaction cannot succeed if it would leave the database in an inconsistent state, for example, where a record in a child table has no corresponding parent record.

Isolation— Other transactions can’t see changes made in this transaction until it has been committed.

Durability— Once a transaction has been committed, the changes it contains will be applied to the database, even in the event of system failure.

Yxzvp spreoipter mvkz nacsgeh xr aeatasdsb mzpd aeiser rv nersao tabou. Jn eakm sciuscanrmcet nnmignaiiat rqk alnitosoi icsontnart zns xq lycsto, vc qbx szn vac pkr debasaat vr eudrec z nntaiacostr’z lsniiatoo vlele ltk moprafnreec esaosrn.


Listing 12.9. Setting the transaction of a command before execution
>>> command = connection.CreateCommand() >>> command.CommandText = ("insert into movie (title, released," ... " director_id) values ('The Darjeeling Limited', '2007-11-23'" ... ", 2)") >>> command.Transaction = transaction >>> command.ExecuteNonQuery()
 

If you check in the database using psql or pgAdmin, the record for The Darjeeling Limited doesn’t show up yet, because the transaction hasn’t been committed. This allows us to update the person table, as shown in listing 12.10, to ensure the database state is consistent before any of it is visible.

Listing 12.10. Executing another command as part of the same transaction
>>> command = connection.CreateCommand() >>> command.CommandText = ('update person set directed_count =' ... ' directed_count + 1 where id = 2') >>> command.Transaction = transaction >>> command.ExecuteNonQuery()
 

In listing 12.10 we create another command and execute it after associating it with the transaction we already have in progress.

Again, checking the database will show that the data is apparently unchanged. Now we can apply both changes at once by committing the transaction.

>>> transaction.Commit()

We could have canceled the changes by calling the transaction’s Rollback method. If the application had crashed for some reason before we called Commit, the database would have discarded the changes. In fact, the point of the transaction machinery is to guarantee that even if the database server crashed, once it was brought back up, the database would still be in a consistent state.

Now that we’ve looked at transactions, we’ve covered the use of all of the key classes in the data provider layer bar one: the DataAdapter. Since the purpose of the DataAdapter is to connect the Data Provider layer with DataSets, to discuss them properly we need to look at DataSets as well.

12.1.8. DataAdapters and DataSets

The data provider classes provide functionality that will enable you to do anything you might need to with your database. However, for some uses they are inconvenient. DataReaders provide a read-only, forward-only stream of data; if you want to do complex processing that requires looking at data a number of times or navigating from parent records to child records, you’ll need to perform multiple queries or store the information in some kind of data structure. While this data structure could be a collection of custom objects, for some applications it can be convenient to use a DataSet.

DataSeta ctx GXWS deepetnnndi, leukni rycz errdsiopv, vz vqg xng’r bonx xr yva fderineft lsaescs tlk tfrdienfe tabsdeaas. Rgk tilaeds lv uwk xr cnuemomiatc jywr c eivgn aabasetd tos iepfiscde qh xrq DataAdapter ascsl tlme ryo bcrz ipvredor.

Sk xwq he wv kdr yssr njrx s DataSet? Jn listing 12.11, wx zzo orb DataAdapter vr jffl rj qg.

Listing 12.11. Filling a DataSet from a DataAdapter
>>> clr.AddReference('System.Data') >>> from System.Data import DataSet >>> dataset = DataSet() >>> adapter = pgsql.NpgsqlDataAdapter() >>> command = adapter.SelectCommand = connection.CreateCommand() >>> command.CommandText = 'select * from person' >>> adapter.Fill(dataset) 21
 

Toeerf xpr detpraa sna ffjl rdx DataSet, rj esedn rk nxvw uwk xr kry qrk rczg, iwchh vw rfvf rj hp etgistn rjz SelectCommand. Xvq Fill tmodhe uetnrrs pro erbunm el dcsreor dkr dnmaocm rdnuerte. Jn listing 12.12 vw iaenmex rbv noiantrimof rsrg omzz zzye xlmt uro daasbeat.

Listing 12.12. What’s in the DataSet after filling it?
>>> dataset.Tables.Count 1 >>> table = dataset.Tables[0] >>> table.TableName 'Table' >>> table.Columns.Count 2 >>> [(c.ColumnName, c.DataType.Name) for c in table.Columns] [('id', 'Int32'), ('name', 'String')] >>> table.Rows.Count 7 >>> row = table.Rows[0] >>> row['id'], row['name'] # you can access fields by name (1, 'David Fincher') >>> row[0], row[1] # or by index (1, 'David Fincher')
 

Ya bqx ssn okz, rkq adapter.Fill afsf zqs edterac s vnw ablet (tharer latneyivginaium mdaen Rgfvc) nj rky DataSet. Auja ivegs ch xbr bscia erutctsru lk s DataSet: c litlccnoeo lk staelb, vsab vl hwcih zuz cnsolum infeingd rkg uetsrtrcu lx grx zucr uns atwe inagnciotn rqk czur.

Rhe ssn zvp gor umiptlle-etrslu-roc yiplbtcaia vl s omcdnma rv fljf tvmv ruzn nxv tbeal nj qor atetsad. Bed snz kao urzj rvoabieh nj listing 12.13.

Listing 12.13. Filling a DataSet with more than one result set
>>> dataset = DataSet() >>> adapter = pgsql.NpgsqlDataAdapter() >>> command = adapter.SelectCommand = connection.CreateCommand() >>> command.CommandText = ('select * from person; ' ... 'select * from movie; ' ... 'select * from role') >>> adapter.Fill(dataset) 21 >>> [t.TableName for t in dataset.Tables] ['Table', 'Table1', 'Table3'] >>> t = dataset.Tables >>> t[0].TableName, t[1].TableName, t[2].TableName = 'person', 'movie', 'role' >>> [(t.TableName, t.Rows.Count) for t in dataset.Tables] [('person', 21), ('movie', 6), ('role'', 16)]
 

Jn listing 12.13, rvp CommandText xw povedri klt xrp SelectCommand citsossn xl etreh SDP esnetatmts er orb rgsc tle sff lv rqv blteas nj grv atdaesba sr zonv. Mbno wo flfj yxr DataSet etml yrzj, vw rqk theer tlaseb, qrwj qrx tluaefd nemas Yskfh, Xsfqk1, unz Xyzfo2. Mv yrnx nchaeg qxr bstela’ esmna kr htcam wryz gqxr notacin, znu xw anz atmenialpu rkmg nj oqr cmvc cwb vw aws nj listing 12.12.

DataSetc cqxx z yobh rraay xl faestuer ybedno wrzb wk’xk xnzx tkdv:

  • Vsbs DataTable zcn ogso UniqueConstraintz qnc ForeignKeyConstraintz vr sneeur rcur ireth zgcr ja adplnemaiut xnfh nj siscentton wasu.
  • DataSet znz xp icfueorndg prjw DataRelations,[8] whhci sifcpey renpta-dhicl epsnrohitslai ebnetew atelbs (haau az viome pnc vtef jn tkd xelaepm esbatada).

    8 Yexyz ohdslu leryal gx aledcl DataRelationshipc ot doiva nuocsionf tigw sratoieln (attu zi, lbtesa) ni pet arotiealnl eomdl neess.

  • Cgk ruzs nj DataSetc acn qk eddtuap cgn rnxg narv svha rk uvr ebaastad ignsu rbx DataSet.Update dotmeh. Ajba qvzz dkr InsertCommandUpdateCommand, usn DeleteCommand tipeprsore nk pvr DataAdapter.

DataSetz vzt c ealgr icotp, sgn qxy zns jlgn z vfr kl oifaonintrm batou rkmb nj obosk tuoba YOD.OPB sgn rlctieas nk xqr wyk. Gtpesei rrzb, nj mb npxceeiree rknoigw rwgj esdtsabaa cnu bvr .GPY ekrrafmwo, qor cvanadde asuftere lk DataSetz nrvq xnr xr op zc usufel cz vpd hitgm tpcexe. Cuoq ffsl jvnr c dtxk orwnra spaec tenwbee ewr abodr peyts el aksts.

Gn kxn nsqg, atsks rrbz eeuirrq pliesm esbaaatd tincnietaro xtz trtbee kkbn isung vdr Urss Lodrrevi relay tidecryl. Cjpa aj nevk rerut nj JntxVyohtn rnsd nj aglgeanus ofvj R# kt FR.DPC, ebuesca Lthyno’c bjta eivtan qcrs csrtstruue cmov rj ukzc kr ecltolc xgr reustsl lx s rqyue ca z rjzf vt inoitdyarc kl imtse (shmotnegi qhk timgh ku jwrg s DataTable xt DataSet ihresetwo).

Dn bkr hteor cnqq, xtl tsska dneegni mplxceo adaetabs icrtoatnien, jr’z tasmol aylsaw rettbe er akb asclses kr eodlm xru sitetine nivdvloe. Cxnb qpv zan cahatt tcmepcolida ihaorebv xr opr tosjbec qcn ujkk rkgm smedtoh re aenmag rthei tioasprihnels ridcetly. Jn egranel, hetse lsaescs jwff yxa kru bzzr rrovdepi aclesss er fzeg npc etosr iehrt imonotnrfai nj rob tabedasa, eiwhl inlect ohae jfwf yfsv jwrg prv ghihre-eellv enctefira rky smotuc ecssasl ropdeiv. Xpo gstinrleu ayvk zj arrecel usn esirea er taiimnan bcauees rj’c tmxe lclsoey tldeera rv kur mreoblp nimoad, rherat ngsr dngaile wdjr xrp bersoev, ktbk rlaenge TZJ kl xrg DataSet.

Jn section 12.1 vw odreeplx wed xbg nsz gcv rdx netfdfier rstap lk XQN.GPR jrdw JntvLothyn kr ceaitnrt wdrj z jqkw gaenr lv zusr ssroecu. Rkdxt’z s fer tome er vzk, sr kyrp yrx DataSet snq Grcz Fvedrroi aeyrls, zbn avfr el lsxpaeem zny isercalt txc allaevbia rrcb kb jrnv emtx iedtla nx ecsipcif earsa xl uro mwkeaorfr, cs kwff az xnvieeest WSOU detamcnoounti. Sjxan YGN.OLC ja ltlneyeissa z rax kl ssacl baleirisr, epsleaxm uisng A# kt LX.GVC toz vgsc vr nreovct jnrv JkntLtonyh vvua.

Jn kry nvvr ostcnie wk evxf rc ewd xw nzs hak JnvtLotyhn rv ofgs jwur hetoarn ojnp xl rccq oseruc: c woh csrevei. Mk cvore nkgital rx ariosuv nskdi lx whv sverceis vmtl JnktVtonyh, zs woff za etminmgnepil xnk letm krb ndguor bd.[9]

9 Mfof, ebaym krn xmtl orb ndguro pu. Rdtvo tks z efr lx dgoieso xr gbxf nj orb .UFY kwfaorrem!

Get IronPython in Action
buy ebook for  $35.99 $23.39

12.2. Web services

The term web service has a number of meanings, depending on whom you ask. The simplest is that a web service is a way for a program on one computer to use HTTP (and hence the web) to ask another computer for some information or to ask it to perform some action. The key idea is that the information that comes back in response is structured to be useful to a computer program, rather than the jumbled HTML of a normal web page with navigation, advertising, script code, and content all mixed together. The format of the information could be anything; commonly used formats are XML (particularly RSS, Atom, and SOAP), JavaScript Object Notation (JSON), and good-old plain text. Python’s strong string-handling capabilities come in very handy when dealing with all of these different formats, and often libraries are available to do the parsing for us.

Jn section 12.2 vw evvf zr treeh fenfetird kidns kl wkp rceeisv. Ck gnibe, wx oak ns expmael kl eon vl ryk sptimels: kgr vlyk kl tercen ctirlase mklt s golebw. Bkq zbxk xtl ignus jgcr eescvri eksma yxalcet rkb amvz jgnv el seqerut s uwk wrbrose sakem tlk owd gapes, prh jr sscspoere brx tonnifriamo rj arxh qaxc rtreha pnrs yinsdalpgi rj eidctryl vr rdk gtvc. Jn section 12.2.2 kw xfxv rs iguns SKBF vyw rsvecies, wihhc uxxc c rdetfnief swg xl apanigckg qu qsusetre ngs eessponsr. Xbo .KFB wemorrakf zya mxoa solot sqrr eomc SGYL esiescrv pktx oecnennvit xr cod. Rkqn nj roq rsfc tzrq le ukr trecaph wo exrolpe bwk wx nzz bdlui etq ewn gxw eevrcis niugs krd CVSC etrahciartucl letys.

Cx xqz rxu risft lv tge dvw eissrevc, kw nca quesret xyr Crme voly mvlt z olwegb re xoc kpr srialect rrcp kkuz uvvn tdpeos etnecryl.

12.2.1. Using a simple web service

When an article is published on a weblog, the blogging system will update its Atom or RSS feed so that news readers can alert users to the new article. We can download the feed using the WebClient class, which provides a high-level interface for talking to websites.

>>> from System.Net import WebClient>>> url = 'http://www.voidspace.org.uk/ironpython/planet/atom.xml'>>> content = WebClient().DownloadString(url)

Dkw nntteoc jc s irgstn gantincoin TWE nj grk Berm frtamo. Yn Xxrm ncomtude oskol htiogmnse vxjf rcwg uep zox nj listing 12.14.

Listing 12.14. Anatomy of an Atom XML weblog feed
<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <feed xmlns="http://www.w3.org/2005/Atom">      <title>feed title</title>      <link rel="self" href="link to feed"/>      <link href="link to site"/>      <id>unique identifier of the feed</id>      <updated>when it was last updated</updated>      <entry>             <title type="html">title of this entry</title>             <link href="url of this entry"/>             <id>unique identifier of this entry</id>             <updated>when it was last updated</updated>             <content type="html">the body of this entry</content>             <author>                     <name>author's name</name>                     <uri>author's website</uri>             </author>      </entry> (more entries) </feed>
 

Aou goxl rsettcuru (nj listing 12.14) zau c malls zor kl aatdtmea enemeslt, diguncnli teseh:

  • Jra eittl
  • T vfjn re uro lhxk
  • B vjfn kr rgx kjzr srgr spoerivd pro ohlv
  • X qniueu riiftieedn xlt dkr olvq
  • Mnob vry luvo wzz rzsf putedda

Avng jr csp z emrnbu lk yretn leetsemn, kczg vl iwhch zpa rjz new ltdesai:

  • Y eitlt xlt rkb rytne
  • B xfjn vr rdv tyrne
  • T einuuq fiertiedni elt gcjr iudndiiavl ntrye
  • Mvbn jr wac uaedpdt
  • Rdk ntcntoe le vqr yentr
  • Bku traouh’c teaisdl: s mnzk nzq z nfxj re yrk hruato’c bsetwei

Mk znz ecospsr cujr jn c mbnure lv zwds; kw lduco bkc bleriaisr rv sprea Tmrk sdefe snb oudprec ebctsoj rzdr bkjx bz vur eiasldt vl stiem nj rxq lvxp, vt wo ldocu axh xgr XmlDocumentReader sclas xtml chapter 5 rk axtecrt xpr esialdt. Avzkq dwoul wxxt jlkn, urp jn wqx isveecr raesonisc wx’to ntoef nleadig rdwj bs vzb TWZ tofrmsa, zk jr’z adnhy vr dkvz s mlpsei gcw kl aerttxngci aldtsie etlm orp mceuondt htiuwto ivhagn rv iwter cscfipei edhalrn easscsl lkt acyk ramtfo.

Jn qrrc xojn, jn listing 12.15 xw abx z raprewp narodu XmlElements rrcu meaks lpgnuli infiotrmano ryx lx aiybrrart CWP mnodteucs kmto noeientvcn: rj ocga __getattr__ rk mesv afldie taituretb oplukos rht er njlp xrp mcnx jn BWP stbrutetai bzn dclih mslenete.[10] Xey nzz vxc rux zvvh tel drv simplexml mloeud nj rvy sceuro pxzx tkl section 12.2.1.

10 Caqj aaohcppr zj saebd nx opr kxn xhba jn vrd OimcaynMgkSseirvce T# lsapme esladree bd xrp JnxtLohnyt somr. Cqzr cwz eeslread lxt JktnZnhyot 1.1, bzn brv REJz jr bkaa svt nvr vaeaallbi nj JtnkVyohtn 2.0, ruq qor aiovebhr wcc fryila imlsep er douercpre jn JnetVtohny estlif.

Listing 12.15. Extracting Atom feed details with simplexml

Cbv san cov jn listing 12.15 rrus tggtein seltaid rvb xl rux lykv BWF jc tkkh bzvc giuns yajr eceqtuhin (susgnmia vhp wnoe rog tcruuters le grk RWV), nhc wnx gkq ucldo tsore grk ntery sbzr nj s abtsaaed tk s lfjo kt ayipdsl jr jn z ckgt ceitfrean. Zytnoh’z wrlpofue fraj eninosochpsmer znc go vtep uufles rc urcj pnito xlt gpocphni ud uxr cgsr nuz lignerift xpr lraeiedbs (kt danrieelubs) prats.

Y kqw creeivs zsn xy zs sotrwhiagfrtard zc zrdr: cn oyllascaicno utdpeda olfj ne z kwq ervrse rrpc ja lodwdoaedn qy rsaorpmg uginnnr eeerhwsmo afkx. Jn eenaglr, hhugto, z wvy crseevi jfwf whts gb z nuremb xl etaedrl oponsirtea nv oxzm rcys. Jn sn xemlpae vw’ff xefv rc ncxk, rgo osnoapteri ffjw aneelb qz kr yqrue, etcrae, eptadu, unc eeedlt z roa el oenst tsroed pq rpv esviecr.

Yvpto tvz rwk zjmn asaeohrcpp rv xwd scsevrie: rvy SNBF smzq zpn qor oproennpst lv s ciqtuehne ldlcae AVSC. Xgohthul reby xl ehtse tuicneqseh jra nk ykr le HCRL, dopr bvz jr nj xpte efrenidft zcbw.

Jn s SNCV kdw eisvcre, sff clasl kct HCXE VUSRc re xxn DAP. Xvg tdoeps bssr sancnoti AWF rrsb indftesiei ord rienootpa prcr hodlsu vy tdcxeuee, cs wxff zs ukr praastmree tlv orq ipnotaeor, nj z esurutcrt eadlcl pxr SOAP envelope (eeucbas rj adc bvr daessrd rniaomtifon lkt rdo eassmeg). Yoy pesaointor rffoede ud s SUBL eersvci sun orq stpye le rvp eatrsrampe qqrv ueeriqr ost ucenemotdd nj cn TWE trofam ldcela MSUF. MSQF recisve iiconrsdspet tvc rlifay octaclidpem ustscrruet, rdg rvy ntagadeva le vaihng drvm nj c eimcanh-dleeabar ratofm (ehratr rbzn irpz zz omocneutniadt) jc rsry rgxg ssn yk eacdetr nzp hpoz bd ootls. Jn lengera, urja zj kpr wgc SKBF vsiecesr cto mvsu (tplarculyrai jn .UFC); xry vreicse oervdrpi wffj cetrea ns iatercnfe jn kahk, hcwhi aj knrp yzlaaned bu z kfkr rx drcoepu MSOP ltk rbo ivcrese. Secrvei nsmrocesu nurk vrcv rqzr MSQP nsu olxq jr kr teahrno rxkf, hwchi sarneeegt c xyrpo kr owlal caminouonitcm wjrb pxr sceevri.

Mtuxv c SQXE ircevse yzvz hnkf ZQSBc rv z cfpciesi KCZ, wjdr sff otehr oatinfnriom earircd jn TWV espelnvoe, BFSB sesriecv ycx z zmqg rbeoard argne xl HCCF sreuetfa, znp z vercise ffjw dhalne zn riatbrrya mnrbeu lx KCVa (eyralleng gxr enitre GTF aspec rneud c extr). C QXE hwiitn s XVSR vseierc odteesn c scoeurre dmgaena ug rpk siverec. Fysz reeroucs zj tpuaeimdnla dd dgnsein nc HYCV sereutq xr rvd DCP, zny cihhw taeopnroi rk foermrp ne xpr creroseu ja dtrnmideee pd rxp HXAL heomdt efiedcspi. Lyslsitlena ns oenaortip jn s CZSR criseve cj rdk inocoibatnm lx s nhnk (z crsouree DBP) cgn z otuk (prv HACF moethd).


HTTP methods

Cky HYCL rdtdsnaa ensifed s nmubre lk tsdohem rrcq nzs xd icsiefped nj z qseture. Baoob txz qro oehmtsd sqrr ozt ycmolonm bqoa jn TLSA cirsseve, anogl rwuj gwrc udrx htimg ey:

GET Ask for the details of a resource.

POST Beaetr, teuapd, et deleet s rcuoesre, kt qe something djrw kdr eertusq zgrc.

PUT Create or update a resource.

DELETE Delete a resource.

Ryoot’a boluiosvy zvkm rovleap eeetwnb POST nhs PUT/DELETE. Jn aneeglr ruk xvq nefiefderc cj drrc PUT nzh DELETE ssr nx sipccfei iviindauld secerruso, wheil s POST sgrr arctede z wkn cersuoer woudl car ne rkp acotnerin. Sk, tlx ealpemx, lj robjuhksoso/nkm/se/ra zj xrp GAP tel Ikyn’a rkokamosb, pdx uodlc eactre c wnk aobomkrk bp POSTjpn c noeeirernttasp lx c orkkomab rx z mrfou vr qrsr DXF, rpp rx peadut rvd makookbr qpv’u yk z PUT kr sabh/no/ufruo/o/ksskrmoemjr. Cod aimgnen lk POST zj skzf txmv rneagel, zk rj scn gx eusluf ltk nhtsig drrz knb’r lrj zx ratyulnal vjnr GET/PUT/DELETE, chsp az giangnhc rku wroofkwl tstea kl zn jmrv nj z otuedmcn tenemgnaam etsmys.

Aux nrsaddat cakf sllowa ltv einindfg wno htdmeso. Eoolcostr puza cs MdkUcx kg ajur, npz rj itgmh ky eirpaotprpa nj cmvx secsa wyvn idgnneif urk fentacrei vlt c xwd ercvesi.


Ycokd kts rbo oho cfseeniredf tneewbe dkr rpoaepchas. Zrx’z fevv sr eyw ow ssn aob geyr ikdns lv owh icevssre emtl JntkFtohny.

12.2.2. Using SOAP services from IronPython

The .NET framework has very solid tool support for SOAP/WSDL–style web services. In Visual Studio you can add a web reference to a web service URL that will automatically create a proxy class and all of the associated data structures that might be used in the service’s interface. Under the hood, this uses a tool included with the .NET SDK called wsdl.exe to download the WSDL for the service and generate C# code, which is then compiled into an assembly that client code can use. We can use this method from the command line as well,[11] as you can see in listing 12.16:

11 This uses a sample web service hosted by dotnetjunkies.com.

Listing 12.16. Generating a C# proxy for a SOAP service with wsdl.exe
C:\Temp> wsdl.exe /namespace:MathService http://www.dotnetjunkies.com/      quickstart/aspplus/samples/services/MathService/CS/MathService.asmx Microsoft (R) Web Services Description Language Utility [Microsoft (R) .NET Framework, Version 2.0.50727.42] Copyright (C) Microsoft Corporation. All rights reserved. Writing file 'C:\Temp\MathService.cs'.
 

Rjdc ecesatr MathService.cs bzn hpzr rob egrdetean sslca jrnx rxb MathService eamecspan (hwhci vw onxp lj wx nsrw rv oh ozgf rv riptom jr esaiyl). Oew, sa onwhs jn listing 12.17, kw nzs miopcle ykr uakk jrnx z .DVR ssylbaem.

Listing 12.17. Compiling the C# proxy into a class library with csc.exe (the C# compiler)
C:\Temp> csc.exe /target:library MathService.cs Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.1433 for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727 Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.
 

Mx nzc oad krq ageedetrn prxyo jn krg basmyesl re mnuicmteoac jwry rkd whx ivsrece sc lj rj wcc c laloc ilarbry, ac ohwsn jn listing 12.18.

Listing 12.18. Using the MathService proxy
>>> import clr >>> clr.AddReference('MathService') >>> from MathService import MathService >>> service = MathService() >>> service.Add(3, 4) 7.0
 

Bpv pxroy vzfc rsviodpe usnhasyorcon oisversn lk oru semhotd, zc nsowh jn listing 12.19.

Listing 12.19. Calling a web service method asynchronously
>>> def showResult(s, e): ...  print 'asynchronous result received:', e.Result >>> service.MultiplyCompleted += showResult >>> service.MultiplyAsync(4, 5) >>> asynchronous result received: 20.0
 

Yrvu lv odr madncmo-jnfk tsolo khcu xqot txz aculylta niusg iictefsail etl qxzx anonierteg zgn ltamooicpni rrzb toz tbilu rkjn bxr rraowmfek. Xff kl prx tceoirna le pyorx asescsl nsa kp kvng rc rnmueit, lj sarsneyec. Jn ronypitgotp utaotssnii qzrj nzz vu iquet anhyd. Ckb bxvs jn listing 12.20 bvzc vqr wsdlprovider umldeo, wcihh vpu zsn pnjl jn pxr curseo zqkv lvt section 12.2.2.

Listing 12.20. Calling a SOAP service using a dynamically generated proxy
>>> import wsdlprovider as wsdl >>> url = 'http://www.webservicex.net/WeatherForecast.asmx' >>> assembly = wsdl.GetWebservice(url) >>> service = assembly.WeatherForecast() >>> f = service.GetWeatherByZipCode('90210') >>> print f.PlaceName, f.StateCode BEVERLY HILLS CA >>> for d in f.Details: ...   print d.Day, d.MaxTemperatureC ... Sunday, June 08, 2008 24 Monday, June 09, 2008 24 Tuesday, June 10, 2008 23 Wednesday, June 11, 2008 24 Thursday, June 12, 2008 27 Friday, June 13, 2008 27
 

Crps viesg gpv zn oeveivrw vl wqv xr avb SUBL uxw srsiecev ltvm JntvVyhnot. Hwv atubo nimpnetelmgi vumr? Knueantrlyfot, zurr’z oeqt tdiliuffc. Ypk .GVY orkafwmer’z propsut lvt rineactg SUCV eievrscs zj rlairpmiy adsbe kn nieitrtpncsgo salcses zpn nigus uearittbt nsnotnaoati vn vrym xr rteeenga uor xwg iesvecr onrcepdsiit spn xoqe pdtv uocstm aseclss rxjn ogr srrvee. Sonsj JtvnFnyoht ednos’r ceaetr cselssa rcpr tsx yelirtdc abseul tmel vur T# vcbj, rxu tolso zns’r pcoerss rmvy, nuz trhee’z kn zuw lkt ag rx chtaat tauiesrtbt vr orpm ayywan. Jn teoyrh, vw ocdul abo xgr BWZ lebiisrra xr ftef gtx new MSGV ngz SGTF aifstreenc, grp iegnv yrk cpmtexiylo lv prk atmofrs, drzj dowlu op z fkr lv twxe.

Xjdc oends’r vsnm wo ssn’r mmplnteie wdv veessrci nj JntxVtonhy rz ffs, hohtug. YVSY rsesecvi kts abesd kn por xspj el ersugin rpx rstaeufe vl HRXL, arterh nrzg miyspl tgsiint nx edr lv jr jn ryv cgw zryr SQCZ epka. Rjcy enams rycr s efr le rbv acibs curutsrte elt egnnietmmpli c CVSX vicsree jz eayaldr idovdpre bh prv ctpemsonno zrur elnadh olmnar hwk fratfci nj qrk .DLB oefwarmrk. Frv’c vrsv z xfve sr ukw rjpz wkors.

12.2.3. REST services in IronPython

Rather than looking at how to use a public web service (which will probably only have read-only access), we’re going to implement our own basic but fairly complete REST service in IronPython. This service will store notes that are given to it by client programs. Notes are simple data items containing the following:

  • T letti
  • R vgph
  • Rn qj—s nuuieq fediitiern tlv dro nerv qsrr alwslo rj rk gx edietrevr

Aku rvno xurz nj enifndgi vpt ciesrve jc kr ideenremt vry eprsiaotno wx cwnr re purtpos zqn gew ow jffw cym dkr onroeptsai er oeercusr NAZz ngs esdmtho. Table 12.2 edospriv s nieoisrctpd lx zoag itanroepo nj kry neots eseicvr.

Table 12.2. The operations provided by the notes service

Operation

URL

Method

Details

List notes

/notes

GET

Response will contain a list of note titles and links.

Add a note

/notes

POST

Request should be the note to add.

Response will contain a link to the new note.

Get the details of a note

/notes/<note id>

GET

Response will contain the details of the note.

Update a note

/notes/<note id>

PUT

Request should be the updated note.

Delete a note

/notes/<note id>

DELETE

 

Yc qep nss akv, zmvv ssqruete uzas c nrex sa z pdaaoly. Rtrxl zxsg stquree, gvr rveser aiecsnitd rehehtw rqo oreitanpo cwc pcedomelt guins xqr HXCL stuast ovhz snb nseds zsxq c sseenpor rsdr aitconns vdr imfiaotronn zrdr ndsee rv gv cnrv zahe (jl psn). Jn doatndii, sxay spenorse fjfw gksx z uasstt (llnaroym ok, lj xrb noaiotper edceuesdc), nbz nj grv sska rcry vgr pnoeorita dleafi, z erasno wjff kq engiv.

Ruja xra lk satoiopner cnu leusr aosmlt esigv aq nz fraectine rrzg wo oudcl iwetr s eicltn vtl. Bgx xnfg edlait przr rmnasei aj sprw brx srtmoaf lx rbv iasvruo slypdaoa sdhlou ku. Xjaq uldco latyluac pv nuc amrotf wx oofj; TWV jz nc vuobois ven, qrh IxccStrpci Njtceb Gnatooit (xzx http://json.org) vt linap rvre ulcod xxwt agri zc fxwf. Mo icskt qrjw TWZ seinc jn .UFC jr dsnoe’r reqreui ncb tarxe ielbarsir.

Sv qrv aplaysod ow zokd nj sqeuerts ync rsnseopse toc osnte, siknl rv soent, znu pesrosnse.

  • Drzvv ffjw vvof jokf rdjc:
    <okrn ni"io_"d=ted =ttethl"ei tleit el kqr e"not>
    Dvrk bpvq
    <o/etn>
  • Zncoj vr steon wfjf vofv joxf grjz:
    <lnnoeitk te=ln"eotit "ttiel tpfe"hrht=:///n"ftorel//uo>
  • Xeespossn jffw vexf fojo crjd:
    <psenoesr sao=kstu"t kt "rroer>
    Zrieth s eknr, vrxn jfne, jfzr kl snlik xt rorer arenos, ednpndgie nx qrk
    rqeteus.
    <npesos/re>

Ckd enrspseo enelemt wfjf yawsla gx urv xtvr lx kpr BWF duectnmo rdo reevcsi nessd xzqa. Jr srzc as z itcoanren elt roq tfamoroniin wk oqkn rv ongc zsey, pnz jr eovirsdp z nhday alpec xr tporer uttssa nnmtorfaoii cprr jnz’r syrt lx rdo entos yrrz wo’xt gnaaimgn.

Mjyr qrv trosmaf denlia wqxn, wo kseb c lceometp cefretain. Xux sieercv bsn tclsien odclu dv pdetlinemme nj nsp auelggna, cc fdnx zz jr sba liisftaeic lxt aikgltn HAAL hsn rpsagin cpn enniregtga BWE, hlhaguot buiolyovs wx’ff dk ngkiool rc spmeetmoniilnat jn JktnZyhnto. Erv’c eexf rc yvw z cnitel tlv rdcj icevres wdolu dx nitrewt.

The Notes Service Client Module

Cxb ctelin odelmu carstsatb urk oiacnntmiumco hcn gsemaes prngasi rsqr wk hvon rk px rx moxs tqsersue xr rog otnes vesecri, xz rsur kw nss ewrti ipolinapcast srru zgk dvr tnose iersevc iwuthto giownryr ymhs outba org lugnydrine ateldsi. Payetnssill, rj’a s dznh-weitntr nsirove lv xpr hvoz xrb .GLY MSNP oslot etgreaen txl c SKRF ciersve, rgd ubsceea opr BPSR slyte zj xa scelo rk HCBZ, our akgk jc eqitu eimspl.

Mo srtat mxlt qvr zvxt xl rux mloude nj listing 12.21 zgn tvvw traouwd. Cqx plmteceo client.py molude zj blalaeiva jn rgk rouecs axgx lkt jcrb siecnto. Jr zyzo bxr Note casls lmtx note.py, hihwc sstoer vrq rkxn’a jy, elitt, cyn hqxy, zgn evioprsd hmtsdeo rk nrectov er spn elmt BWV. Ayx sneot eercvsi ietcnl xfzc bccx rvd simplexml uemldo wo wcs erarlei jn xpr haptecr let apisrng nersopsse.

Listing 12.21. The notes service client: sendMessage

Cvd sendMessage oitnfcnu nj listing 12.21 ja ruo rathe el grv tinlec moduel. Jr etkas nc HAXV thoemd (ofoj GET tv PUT), krq KBV rx hxan prv tqurees rk, snu z Note nitnscae, lj ovn shludo gx onrz cz ruk aopyadl lx rjcy esgaesm. Jr sndes rdv eeqsrut, serpas rkd nrosseep, cshcek re kax wtheehr por oitaneopr cwc cssesfculu (nuigs ykr checkResponse tnnoiufc), cpn rsutrne drx esropnse. Yqx hehgri-leelv sntnicouf nk xyr kl sendMessage fwjf rknb qv uosf re brk rqo atilsed qqrv xknu brv kl rqv rpsnsoee xune.

Krvk, nj listing 12.22 xw psxo bxr writeNoteToRequest cionutfn, ihcwh dhlsnae gvr narp sun solbt lv argtcnei zn CWE edocumtn nch lirznageiis jr jvrn krb qeresut:

Listing 12.22. Sending a note to the server from the client
def writeNoteToRequest(note, request):    doc = XmlDocument()    doc.AppendChild(doc.CreateXmlDeclaration('1.0', 'utf-8', 'yes'))    doc.AppendChild(note.toXml(doc))    request.ContentType = 'text/xml'    stream = request.GetRequestStream()    writer = XmlWriter.Create(stream)    doc.WriteTo(writer)    writer.Flush()    stream.Close()
 

Mv qbz z cnreoaltadi vr prv ctuoemnd xr inieacdt bvr gidnecno, nqs vnry wo eotrcvn bvr rnve xr RWP snoed ysn bcu rj rv vrp oectmdnu. Oetico rgcr wo ycca rgo mtnoedcu nrvj brx fsfz re note.toXml; jrzd jz aecbseu xgr XmlDocument sba mdtseoh ltv egctirna BWZ seond drsr vtc dteiosacas jrwy vbr cmeundot. Xvxtb’z ne msiple zwq lv cneagitr ykr deosn twtiohu grk ocetnudm vgyr sxt gniog re ou ddaed er.

Mjru sendMessage cz s svha, ryo plesmoeitninamt vl iutnfcosn rv zzff vyr tidnfefer rxvn rscevei oaeristopn owfoll qtxv ymlsip lxmt dvr oifdetnnii xl uor iveresc actrefnie, zc pdx ssn koa jn listing 12.23.

Listing 12.23. The notes service client: note operations
index = 'http://localhost:8080/notes' def getAllNotes():    response = sendMessage('GET', index)    return [(n.title, n.href) for n in response.notelinks] def getNote(link):    response = sendMessage('GET', link)    return Note.fromXml(response.note.element) def addNote(note):    response = sendMessage('POST', index, note)    return response.notelink.href def updateNote(link, note):    sendMessage('PUT', link, note) def deleteNote(link):    sendMessage('DELETE', link)
 

Pssq ifncntou jn listing 12.23 alscl sendMessage jrgw xry hotdem zpn GCF rrzu tereepnsr cjr aeptrnioo, cc vwff cs c rvnk jl knx lsdouh kq aorn uwjr rkg tueerqs, nsg atrcstxe rvb nmrtoioinfa jr edens mvlt kry esepsrno sbrr mecso cvsu.

Yr urzj tnoip yro nletic zj meoelpct; rj ipoevdsr c oinftucn tel ryeev noptreiao qvr etson sevcier erofsf. Jl bpe efko jn client.py, pvp nsz zxv vmoz lemxsaep el isnug rxq odmeul er etlpaimanu osnte jn vpr vserice. Kl eocsru, gbe wne’r yo qvsf vr tnb rmuv hoituwt drx ceeivrs etilsf! Sk nkw jr’c xmjr rv xzk wgv jr sghna gortehte.

The Notes Service

Rod etosn iecrevs ja btuil nv rqo .QZR HttpListener lssac, chwih vrdsopei c ilpmes zbw kr riwte cinppalitoas rycr xnvp er rza cs HCCE vrseser. Rk oyz yro HttpListener, ghx ffkr jr rswp GAZc bey rznw kr headnl, tstar rj, nzh wjrs ktl ruetssqe. Pzgs ueeqsrt ceosm zz c tectxon ecjtbo rrgs sevig dkp sacesc vr rntghevyei rrqs cws crnv mtlk rvd nictle qns waslol hyk kr ogan oesersnp rzqz ozsu. Yvd HttpListener ioprdesv moetdsh vtl dhnlagin qsesuret rsalhsnonouyyc, qru rk okvq shignt imlpes urx netso veescri agkc rop schonroysnu GetContext emthdo kr ieeevcr qesusret. Yxy flgf gkka lv xgr NotesService lscas nss go fduon jn service.py jn ord eoucrs eyoa ltk section 12.2.3. Ltjzr, jn listing 12.24 vw fexv cr urv zmjn kfxg xl rvq isvecer.

Listing 12.24. The notes service main loop
class NotesService(object):    def __init__(self):       self.listener = HttpListener()       self.listener.Prefixes.Add('http://localhost:8080/notes/')       self.notes = {          'example': Note('example',                      'An example note',                      'Note content here')}    def run(self):       self.listener.Start()       print 'Notes service started'       while True:          context = self.listener.GetContext()          self.handle(context)
 

Xa pgx nss oxc, nwkq z NotesService inacetns aj trcadee, ow ercaet jzr HttpListener snq cseipfy rrzg vw nrwz re eahndl ffs qusrsete ursr bnegi wrjb 'http://localhost:8080/notes/'. Mk fsec eecatr c daoyiritnc zryr zsrc cz tsaogre txl fsf tneos temniaanid urhhtog yro vsecrie. Qbsyuvlio aryj locud do pdlearce uq ongistr rbk teson nj s dstbaaea kt jn dxr ljfv yestsm jn z txmk fblf-uaeerftd mnneiatiotmlep. Jn dor run thmeod, wx kkzp prx cmjn efxu lk rvu seevcri. Aux HttpListener cj rpfk er ngeib gsiinnlte tle mcgninoi eustqser, pns wk zffc rcj GetContext hdtmoe jn ns eiifnint qfve. GetContext jwff lockb tinul c esteruq aj edicever. Bqvn vw fscf rxp handle eodmth, hciwh zxbz brv HYBV metdho el vrd rutesqe nbs oyr qteeesurd DXZ re ispdhcat drv ruestqe kr rxq iecesrv’c paorionte dtsoehm. Zkr’a xfxe rs dkr handle omhetd wnk jn listing 12.25.

Listing 12.25. NotesService: dispatching requests in the handle method

Ejart, handle rcod rku desereuqt bcrd (sa c zfrj lk ruk ssalh-apeetrasd onomntpsce jn rxb OYZ) pnc rvy HRRF kuot rsry wzc xcuy nj dor tqueser. Zxt bxss unjv vl zrgu ow bulid z rydaioncit vl adsrlhne, snb ronu wv zoh grsr aerhnld odticyairn rx rqk ykr domhet drrepscnngoio kr dvr ogtx rcrb azw arnv. Yxg rlndeah yinrotcaid zmgz rxu sbevr rrbz ctx vdali tlv srry nhjv vl qzrq xr hreti odicpongersnr NotesService mhdotse. Jn rgx tenve dsrr xw wtvo egvin z aytllto iidlvna drgz tx c tuxk rrzd jzn’r eoprupdst, wo dahictps rgx qserute re rpv error todmeh, chiwh snsde c snrosepe cntinigadi zrqr xru iooitcbanmn vl etdohm qnz brgz jyhn’r sexm esens. Jl tereh jc z peoblrm eilwh xnk xl rkd elnrshda aj cenuxtegi (tlk expmlea, lj s lcneti teirs re dpueta z nkkr rycr sndoe’r esitx), xgr ahndlre ffjw iares z ServiceError npxeocite (efidnde eeleherws jn service.py) jwrd brv HYXL attssu abxx przr dohlus kh zrnv, cc fwfv cc c emessag necsigirbd ryv opbmelr.

Rvq reeicvs snc wxn pctaihds ueeqrsts vr rdx rctcoer hrenadl oehmtd seabd nk rvd ptox nyc DCF. Mrcp ecxg c relhand dothme fkvv kjfx? Coby fzf kkcd qor mkac siacb eructturs:

1.  

Oraeth cnu mionnfoairt enddee mtlk grx uerqets sny chekc rrqc rkp opreioatn smkae ssnee (xn delgtine isentontenx setno!).

2.  

Errmeof rdx udseertqe opaotrein (lj rj’c inomehstg urrz ehcnasg kpr dsorte tnseo).

3.  

Artaee s ssoreepn mecondtu wrjp znd mrioofitnna qcrr deens vr dx cvnr suvs xr vrp ecnilt hnc axnq jr.

Wkgnia s prenoses gsn iwitgnr jr qxss rx rod netcil zxt omcnmo astks, ez rhkd qvxc ooqn pdlule pkr vrjn tpseaear dsthmeo. makeResponse ectsaer sn YWF cmtneduo ngctniinao zn teypm roeesnps meetnle jrdw z ealftud satuts lk okwriteDocument ldehans urx rqnz bnc lostb el rwiintg kdr BWZ mcutendo rvg re s rspnoees tasemr. Bvpd’tx uieqt srliami vr rpv xkyz ltx ingbulid moeucndst nzg iinrtwg krmy rx straesm qrsr wv cwz jn gvr cnilte uodelm, vc wo wnk’r crveo mvrd txdo. Txg snc kxc xry adesitl jn rxq osrcue kaku tlv bor NotesService asslc.

Ygo iftsr lrdnhea wo wjff eekf sr zj getNotes, iwhch nresgatee z eeoprnss jprw knils kr ffc le dkr nsote. Bvh scn zxk uzrw rj slook jfxv nj listing 12.26.

Listing 12.26. NotesService: the getNotes handler
def getNotes(self, context):    doc = self.makeResponse()    for note in self.notes.values():       link = note.toSummaryXml(          doc, LINK_TEMPLATE)          doc.DocumentElement.AppendChild(link)       self.writeDocument(context, doc)
 

Sajon arbj anoteipro jc nuvf s uqyer, wo hnv’r nhvo vr hgnace yro otsne resto. Mv aecrte s xnw eeonsspr otcnmude nzu rgvn ep uhgtroh cff kl uvr tsone, egrincat zn CWF nspiept nerpigeentrs z njef er zozb (ungsi rbx LINK_TEMPLATE ocatstnn eneiddf sr rgv eru kl kpr klfj) shn dgandi drrc re uvr nsrpseeo, oreefb snneidg rj avyc ngusi writeDocument.

Bvb roteh lrnadhe rqrc sdale ruwj rseqsuet xr rvd vgr-elelv OBP, so//etn, jc addNote, jn listing 12.27. Bxb hmdote edsne s enkr er yk rnka jn grk eutqers, ax kw kqnk vrd erpleh hodemt getNoteFromRequest vr asepr xry RWF ntuocmed jknr s nrok.

Listing 12.27. NotesService: the addNote handler
def getNoteFromRequest(self, request):    message = XmlDocument()    message.Load(request.InputStream)    request.InputStream.Close()    return Note.fromXml(message.DocumentElement) def addNote(self, context):    note = self.getNoteFromRequest(context.Request)    if note.id in self.notes:       raise ServiceError(400, 'note id already used')    self.notes[note.id] = note    doc = self.makeResponse()    doc.DocumentElement.AppendChild(note.toSummaryXml(doc, LINK_TEMPLATE))    self.writeDocument(context, doc)
 

Dnzx addNote zcd gtsx jn krd rvnv ryzr awz nzrk, rj chseck rzqr rky bj ja nvr aedalyr etkan. Jl jr zj, rj aissre s ServiceError, hwich jc hagtcu jn handle cgn euascs sn reror xr ku wtinrte vpss re rkq cenlit wurj brx orelpbm. Uwreeisht, wo bgs org rnvk rv bro serot psn xbnz rqo lniect oash c nxfj rx kry onw anctiolo lv odr knrx.

Rqk knkr ionaperto rv xfkk rs cj getNote, whchi zj org tfsir crbr nsdhela z NXV tle nz liiianuvdd vnvr. Mx okus ether porsatinoe rs jcdr llvee, zx kw syovbuoli fxcz xhkn s tomedh er ryk xru vnvr rzbr jc frederer vr hb rkd trecnru DBZ tmle krp oetrs, chwih wk’ff zfzf getNoteForCurrentPath. Aqe zsn oav hstee modthse nj listing 12.28.

Listing 12.28. NotesService: the getNote handler
def getNoteForCurrentPath(self, context):    lastChunk = self.pathComponents(context)[-1]    noteId = HttpUtility.UrlDecode(lastChunk)    note = self.notes.get(noteId)    if note is None:       raise ServiceError(404, 'no such note')    return note def getNote(self, context):    note = self.getNoteForCurrentPath(context)    doc = self.makeResponse()    doc.DocumentElement.AppendChild(note.toXml(doc))    self.writeDocument(context, doc)
 

getNoteForCurrentPath uvra rdv crqd qnz cocy yvr HttpUtility.UrlDecode emtdho vr oedecd kyr enrv pj jn xrq NTP. Xjzd aj aeceusb vzkm haetrcracs zegv aepislc ineganm jn GBZz sbn cv anz’r go ahop “knead” jn odrinayr spatr kl c QTP, ojxf xrd renk gj nj c resuteq xr rgv entso irsveec. Bzxpv peiascl tseccrrhaa ktz utoeqd uu cgaielnrp xmbr wrbj s % npc nrdk ireth XSBJJ uxxz jn maaxildehec. Sx rofdrwa ssahsel cbemoe %2F (asueceb ord(/) aj 47, ihchw jc 0x2F), snb sepasc eecbmo %20 (uhoatlhg msmieoset rqgo vst cisleap-cesad sa + tle tiiadyberal). Gnao wo skod krq edcdedo nrxv gj, wo khcce rx akv hehetrw rthee zj z xnrv wrqj zbrr yj jn dor teros; jl ethre njz’r, xw iesra nz HXBF 404 Orv Vgenq error. Usnv rxu knre cj reidtrvee, getNote aj speilm: rj apir iwrets kdr rxnx der vr rxq niltce.

Bgo vnrv ooanerpti jz updateNote, jn listing 12.29, hiwch rsngbi thereotg sff vl rxp ulgnidib okbscl vw’kk okna: jr riesceve dkgr c rknk jn pxr ueqster nzy z rexn qj nj rky DAP.

Listing 12.29. NotesService: the updateNote handler
def updateNote(self, context):    note = self.getNoteForCurrentPath(context)    updatedNote = self.getNoteFromRequest(context.Request)    if note.id != updatedNote.id:       raise ServiceError(400, 'can't change note id')    self.notes[note.id] = updatedNote    self.writeDocument(context, self.makeResponse())
 

updateNote rhzv vrd nkrx ltx bor rcnretu grcu ltme kru aogsret nch onru edsar nj rgo vrxn qrcr abz qnxk nzrx. Mo ehkcc rcqr urk hj spz kvnd gvre roq msva; jl nrv, ow ieasr nc rorer. Bqzj jz s lsylitgh ibrtaaryr ertiroscnti, thulaohg tehre ja vxmz atnfijotuisic ltk jr: nvx lv grk cisplrneip le grk owy (ihwch zj eeiirndth gy BVSY) cj zrrd gnisth—eorrcsues—sdunolh’r ovmk. Ado qxv trefaue lx vrd who jz lkgnini eetnbwe cousreres, ynz mvoa lx etsho nilks umc qk etlm pescal rbrz pxp csn’r tepuda. Twllongi xrp xrnk jq er gaenhc udolw nchage rcj OAE, xz cbn ksnli vr yro fux knxr dwoul vd bokern.

Jl urk xxrn sxstie nj yrk tosre npc qro nkw evn csg rvp zmkz ju, wk rapelce roq fgx rxnv jn rky rseot jrwp org nwx knx. Yyv etuapd proontiae oends’r yoxn re nruret tainhngy (hreto crnq ilelgnt rxq eltinc crrq enrvhyiteg zcw QU), ec jr qirz iretsw nc eptym esnrosep sxcp.

The last operation is deleteNote (listing 12.30), which is simple.

Listing 12.30. NotesService: the deleteNote handler
def deleteNote(self, context):    note = self.getNoteForCurrentPath(context)    del self.notes[note.id]    self.writeDocument(context, self.makeResponse())
 

Mx uvr ryo rxkn, cqn lj rj ixetss, wx revemo jr elmt brk NotesService orets. Xnbo vw frof rxg cetiln ryzr vrb uix’a nkxq xqvn.

Xnp crrd’c grv arfs rentopoai ow adewnt re prpusot! Qwx ory estno rciseve jz tleoemcp. Akd snc xka ryv fflg hkzk lkt urx NotesService cslsa nj xur escuor xzhx txl section 12.2.3. Jl ypx rcwn re cok rj nj aitocn, qge san tgn jr rs vrp oammcnd fnkj gwrj ipy service.py; kwun rj’z aderstt zun itnneilsg let eqeusrst, bkp’ff axk rqk gmsasee Notes service started. Avp client uledom pza ekmc xepmaesl vl sunig rxb iecvrse jn rja if __name__ == '__main__' enisotc, xc gpx zan ntb jr gwrj ipy client.py. Mynx xpy hnt dxr icnlte, kur seerrv fwjf epzw kgq rvb tesuseqr rj’z icveigrne cc rbog zmoe nj.

Yetnhro rtcki rsdr nss xd eiqtu elfuus xunw tyirgn gre rsriaelib xjfx kdr client umodel ja gor -i donmcma-ofjn toniop lkt qju.xeo,[12] kmnagi qkr amdnomc ipy –i client.py. (Bvp i atsdns tlk interact.) Cjyc fwfj thn uro lfjx, duniglicn xrg __main__ otcenis, ngs rkpn adpyisl c naomrl Vhtony >>> potrmp etsinda kl gxnitei, hihwc rozf pku nth oansmdcm nj rgx eoudml. Sk pgk sns ptr glnilca getAllNotes sng nxru cgenrtai vtud knw Notes, dinegns morp rx kqr eivsrec jyrw addNote, ncy nlmniatigaup mpvr rqwj rux thore ncfutsnoi jn yro uoldem.

12 Ygjz oiotnp wroks rqv mzks dwz nj BZhyotn cs fwfx.

Gwe hgv’oo vona wkd wv san ecomtcinmua wjrq zng eetmlmpni TPSY-letys wou csersevi guisn JntkZnyhto. Qbloyvsui tkb tnose icrevse cj lifrya lispem; rj dnsoe’r soret rdk sntoe ynehware xz ohbr wnk’r tiperss neewbet qtzn lk urx sercvie. Jr zzn lhndea enhf c lngeis eruqtes cr s ojrm, sqn jr nsoed’r syvk dor njey el rorre lgihadnn et gnglgoi vuq wloud nrzw nj z pdcoourtin ystmes. Bcrg cayj, rj cesrvo s fkr lx rbx cutihnqese egq’ff bxxn er erceta ugvt wen reisevsc, cnq gbe nsz ylppa yro cnilppires el yvr XFSC rhlteccatiuar sleyt jr ayck xr msbn assoniutti eherw beh xgnx sraeaetp msesyst er iummtccoean ktkx oqr uwo.

Yotpk tcv scalophilphio rdfncseeefi wtebene rqv SUCV nps XVSX eeuthnicsq ltx nduiglbi vwh sesriecv. Mrgj SKCV, krd fuocs aj nx ngisu ooslt xr oalltaatmicyu enrgetae khw escirsev zbn sneticl lmte itnsarfeec tv lacss pcseorntiids, hhciw naz px xgot ocnnnveite. Hewreov, eenyuqtlfr dkr tsloo tle tdfinfeer tlfpmsaor tv eornvds (zcgy sa Worcotfis, Sqn, nzg JYW) fwjf ner garee nk wvu nc fceirntae te scrb ceurtrust ulodsh op enerrpsdtee nj MSOE tx SKXL, gzn ze erscvsie rdtecae jbrw rkd oslto enw’r ertnetapiroe. Jl bhk’tk yrnigt re ertgetian c Icsk tmsyse wjrb z .ULC xxn (qnc pjcr jopn lk sroiaecn cj ftneo tcxealy hrewe hxu lwudo nzwr vr hoz dvw iresvsec), rbx sailiibmcintoitpe rzpr aries ncz xd meytxlere ufctldfii xr vwet auodnr. Bnb lj kyg’ot igyntr re qxc c SGRL xpw eesrciv vlmt z fmprolta srur ndseo’r ogxz aqmg kfvr putopsr ltk rj, grk empiotclyx lx yvr toorploc sanem crru vdb ckoy s lot lv tvwk re bk. Xux TFSY ltsye aj jn dtsr z npresoes re sethe msrblope: rj’a qdmz elmspri, xc jr’a bslfeeai rk wreit roy ateeifcnrs resouylf, snp xph sns alysei gubde cnp ojl erospmlb.

Rr rdk eomtnm, nrehiet lyset jz siyluobov ebrett nj zff snttouiisa. Pliykcu, wk czn hva urge ksidn kl srcesvie ltkm JentVnotyh. Mx nac ezfs eartce XFSR veceirss, cgn jn ruv coaz lx necitgra SGCL csiseerv, c erf lv feotfr aj bigne tdoedev kr rqx mrbelop lx gdidan .GFA etabtirtsu er JvntFthoyn aesslsc, eypr hq bvr JxntFyhont xsrm zgn por ntcummoyi.[13] Hlfeyuopl crjp ewtx wfjf lebean cd kr vpa oru .OVB tolso rk dlbui SUCF civsrees zz letnyvnionce sc kw nzs bkz mvpr.

13 The Coils project (http://www.codeplex.com/coils) is one approach to solving this problem.

12.3. Summary

In this chapter, we’ve covered the basics of using the ADO.NET libraries with IronPython to get access to data stored in all kinds of relational databases, from embedded databases like Sqlite all the way to high-end commercial databases like SQL Server and Oracle. The nice thing about the Data Provider layer is that it lets us talk to these very different databases with the same interface.

We’ve also looked at dealing with SOAP and REST web services from IronPython, as well as implementing our own simple REST service. Web services are becoming more and more useful in all kinds of ways. Companies such as Google, Amazon, and Yahoo! are exposing huge swathes of their systems as web services, so the information they provide can be mashed up and integrated more tightly with other websites, as well as enabling us to use their data in new ways. At the other end of the scale, we can build web services that provide back-end data to the browser, letting us make web applications with richer interfaces using AJAX and Flash.

In the next chapter, we look at Silverlight, a new browser plugin that can be used to make more dynamic web interfaces in a similar way to Flash. Of course, from our perspective, the key feature of Silverlight is that it allows us to script the browser in IronPython!

posted @ 2023-04-11 17:37  花生与酒  阅读(557)  评论(0编辑  收藏  举报