Service Oriented Architectures for the Web Service Oriented Architectures for the Web Further Web Services Dr Kevin McManus http://staffweb.cms.gre.ac.uk/~mk05/soa © 2015 University of Greenwich 1 Service Oriented Architectures for the Web Talk About... • Continuing from the previous PowerPoint DOM programming to look at Web services with .NET and PHP • slides 3 – 14 were covered in greater detail earlier • This time running from live HTTP servers • With DOM programming to restructure and combine XML © 2015 University of Greenwich 2 Service Oriented Architectures for the Web Visual Studio Ultimate 2013 fire up VS Ultimate with a new C# project Web Services are not on the Framework 4.5 menu so choose Web Application untick this © 2015 give it a sensible name and location on your I:\ drive as this maps to the stuiis.cms.gre.ac.uk HTTP server University of Greenwich 3 Service Oriented Architectures for the Web Visual Studio Ultimate 2013 choose no authentication choose Web Forms untick press the button and send email to request application root on the IIS server plenty of new to 2013 stuff to sort out before we begin © 2015 University of Greenwich 4 Service Oriented Architectures for the Web skip the intro because real programmers don’t ask for directions © 2015 University of Greenwich 5 Service Oriented Architectures for the Web build the project choose your favourite ASP.NET active web pages are .aspx files all of this code is generated for you © 2015 University of Greenwich Default.aspx is the default home page 6 Service Oriented Architectures for the Web ASP.NET Web Site this URL is correct but this is what happens when the application root is yet to be published © 2015 University of Greenwich 7 Service Oriented Architectures for the Web ASP.NET Web Site once the application root is published we see the now familiar responsive adaptive placeholder running from a live URL © 2015 University of Greenwich 8 Service Oriented Architectures for the Web no need to press the stop button as we are running live dive in, hack it about, and rebuild with cntrl shift B then refresh your browser © 2015 University of Greenwich 9 Service Oriented Architectures for the Web ASP.NET Web Site finally, a relatively simple website © 2015 University of Greenwich 10 Service Oriented Architectures for the Web Add a Web Service right click the project in the Solution Explorer and Add -> New Item .NET web services are .asmx files give the service a sensible name © 2015 University of Greenwich 11 Service Oriented Architectures for the Web add some usful libraries to your new Web service rebuild and refresh your browser to make sure that HelloWorld is working before diving into some code © 2015 University of Greenwich 12 Service Oriented Architectures for the Web you may well need to add some stanza’s to your Web.config file <protocols> <add name="HttpSoap"/> <add name="HttpSoap12"/> add some stanzas to <add name="HttpGet"/> Web.config and rebuild <add name="HttpPost"/> </protocols> © 2015 University of Greenwich 13 Service Oriented Architectures for the Web use this database table as a data source © 2015 University of Greenwich 14 Service Oriented Architectures for the Web .NET DataSet Web Service using System.Data; using System.Data.SqlClient; instantiate a SqlConnection [WebMethod] to SQL Server public DataSet lookupDataSet(string surname) { string conString = "server=sql-server;integrated security=SSPI;database=mk05"; SqlConnection sqlConn = new SqlConnection(conString); instantiate a SqlCommand to hold a SQL query SqlCommand sqlCmd = sqlConn.CreateCommand(); sqlCmd.CommandType = CommandType.Text; sqlCmd.CommandText = "SELECT FamilyName, GivenNames, Telephone FROM mk05.Directory WHERE FamilyName LIKE '%"+surname+"%'"; SqlDataAdapter dataAdptr = new SqlDataAdapter(); dataAdptr.SelectCommand = sqlCmd; DataSet dsStaff = new DataSet("phonebook"); dataAdptr.Fill(dsStaff, "staff"); return dsStaff ; } instantiate a SqlDataAdapter to run the query and a DataSet to hold the results return the DataSet © 2015 University of Greenwich 15 Service Oriented Architectures for the Web lookupDataSet() the DataSet is returned as XML with a schema included good but not what we want © 2015 University of Greenwich 16 Service Oriented Architectures for the Web .NET XML Containers • Three XML document stores each with different features • XmlDocument • the primary document store • supports W3C standards for XML document (DOM), plus useful additional features that make it easier to access the contents • XmlDataDocument • provides a bridge between XML and relational data by allowing the content to be accessed as a DataSet instance as well as a standard XML document • XPathDocument. • fast and efficient document store designed to be accessed only using XPath methods and the XPathNavigator • XPathNavigator can be used over any of the three document stores © 2015 University of Greenwich 17 Service Oriented Architectures for the Web Telephone Directory Web Service • Re-write the web service to return an XmlDocument • instead of a data set • Convert the data set read from SQL Server into a string • Load the string into an XmlDocument © 2015 University of Greenwich 18 Service Oriented Architectures for the Web .NET XmlDocument Web Service using System.Xml; instantiate a SqlConnection to [WebMethod] SQL Server public XmlDocument lookupXmlDocument(string surname) { string conString = "server=sql-server;integrated security=SSPI;database=mk05"; SqlConnection sqlConn = new SqlConnection(conString); instantiate a SqlCommand to SqlCommand sqlCmd = sqlConn.CreateCommand(); hold a SQL query sqlCmd.CommandType = CommandType.Text; string sn = surname.Replace("'", "''"); sqlCmd.CommandText = "SELECT FamilyName, GivenNames, Telephone FROM mk05.Directory WHERE FamilyName LIKE '%"+sn+"%'"; SqlDataAdapter dataAdptr = new SqlDataAdapter(); dataAdptr.SelectCommand = sqlCmd; DataSet dsStaff = new DataSet("phonebook"); dataAdptr.Fill(dsStaff, "staff"); XmlDocument xmlDom = new XmlDocument(); xmlDom.LoadXml(dsStaff.GetXml()); return xmlDom; } © 2015 University of Greenwich instantiate a SqlDataAdapter to run the query and a DataSet to hold the results instantiate DOM, populate it from the data set and return it 19 Service Oriented Architectures for the Web lookupXmlDocument() clean XML returned we could easily manipulate this XML further using DOM programming © 2015 University of Greenwich 20 Service Oriented Architectures for the Web lookupXmlDocument() XML is pretty printed but this whitespace could cause problems © 2015 University of Greenwich 21 Service Oriented Architectures for the Web XML Schema as DTD – directory.dtd <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE directory SYSTEM "directory.dtd"> <directory> <person pid="FXC1" loc="Fox"> what if the XML schema we <firstnames>Stewie</firstnames> want does not match the <surname>Griffin</surname> namespace or structure <telephone>6578</telephone> </person> from the database? <person pid="HBC6" loc="Hanna-Barbera"> <firstnames>Betty</firstnames> <surname>Rubble</surname> <telephone>8719</telephone> <!ELEMENT directory (person*)> </person> <!ELEMENT person (firstnames, surname, telephone)> <person pid="WBC8" loc="Warner Brothers"> <!ATTLIST person <firstnames>Bugs</firstnames> pid ID #IMPLIED <surname>Bunny</surname> loc CDATA #IMPLIED <telephone>1940</telephone> > </person> <!ELEMENT firstnames (#PCDATA)> </directory> <!ELEMENT surname (#PCDATA)> <!ELEMENT telephone (#PCDATA)> © 2015 University of Greenwich 22 Service Oriented Architectures for the Web lookupValidXmlDocument() while we have no attributes this is valid against directory.dtd © 2015 University of Greenwich 23 Service Oriented Architectures for the Web .NET Valid XmlDocument Web Service [WebMethod] public XmlDocument lookupValidXmlDocument(string surname) instantiate a SqlConnection SQL Server { string conString = "server=sql-server;integrated security=SSPI;database=mk05"; SqlConnection sqlConn = new SqlConnection(conString); instantiate a SqlCommand SqlCommand sqlCmd = sqlConn.CreateCommand(); sqlCmd.CommandType = CommandType.Text; hold a SQL query string sn = surname.Replace("'", "''"); sqlCmd.CommandText = "SELECT FamilyName, GivenNames, Telephone FROM mk05.StaffList WHERE FamilyName LIKE '%" + sn + "%'"; SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = sqlCmd; DataTable dt = new DataTable(); da.Fill(dt); to to instantiate SqlDataAdapter to run the query and DataTable to hold the results instantiate DOM with root element <directory> XmlDocument xmlDom = new XmlDocument(); xmlDom.AppendChild(xmlDom.CreateElement("", "directory", "")); XmlElement xmlRoot = xmlDom.DocumentElement; XmlElement xmlStaff, xmlFname, xmlSname, xmlTel; XmlText xmlTxt; string fname, sname, tel; © 2015 University of Greenwich create some handy variables for what follows 24 Service Oriented Architectures for the Web .NET Valid XmlDocument Web Service foreach(DataRow r in dt.Rows) { fname = r["GivenNames"].ToString(); sname = r["FamilyName"].ToString(); tel = r["Telephone"].ToString(); loop over all rows in the DataTable xmlStaff = xmlDom.CreateElement("person"); xmlFname = xmlDom.CreateElement("firstnames"); xmlTxt = xmlDom.CreateTextNode(fname); xmlFname.AppendChild(xmlTxt); xmlStaff.AppendChild(xmlFname); xmlSname = xmlDom.CreateElement("surname"); xmlTxt = xmlDom.CreateTextNode(sname); xmlSname.AppendChild(xmlTxt); xmlStaff.AppendChild(xmlSname); xmlTel = xmlDom.CreateElement("telephone"); xmlTxt = xmlDom.CreateTextNode(tel); xmlTel.AppendChild(xmlTxt); xmlStaff.AppendChild(xmlTel); xmlRoot.AppendChild(xmlStaff); } return xmlDom; extract values from each row into handy variables this is boilerplate code for stiching together an XML DOM as a hierarchical tree return DOM to the client } © 2015 University of Greenwich 25 Service Oriented Architectures for the Web .NET Valid XmlDocument Web Service • The boilerplate code to construct an XML DOM object is something that will become very familiar • Let’s add some more code to add attributes into the DOM © 2015 University of Greenwich 26 Service Oriented Architectures for the Web .NET Valid XmlDocument Web Service [WebMethod] public XmlDocument lookupValidXmlDocument(string surname) { string conString = "server=sql-server;integrated security=SSPI;database=mk05"; SqlConnection sqlConn = new SqlConnection(conString); SqlCommand sqlCmd = sqlConn.CreateCommand(); sqlCmd.CommandType = CommandType.Text; string sn = surname.Replace("'", "''"); sqlCmd.CommandText = "SELECT id, FamilyName, GivenNames, Telephone, Location FROM mk05.StaffList WHERE FamilyName LIKE '%" + sn + "%'"; SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = sqlCmd; DataTable dt = new DataTable(); da.Fill(dt); this is much the same as before but with more data included in the SQL query and some more temporary variables XmlDocument xmlDom = new XmlDocument(); xmlDom.AppendChild(xmlDom.CreateElement("", "directory", "")); XmlElement xmlRoot = xmlDom.DocumentElement; XmlElement xmlStaff, xmlFname, xmlSname, xmlTel; XmlText xmlTxt; XmlAttribute xmlPid, xmlLoc; string fname, sname, tel, pid, loc; © 2015 University of Greenwich 27 Service Oriented Architectures for the Web foreach (DataRow r in dt.Rows) { fname = r["GivenNames"].ToString(); sname = r["FamilyName"].ToString(); tel = r["Telephone"].ToString(); pid = "GWS" + r["id"].ToString(); loc = r["Location"].ToString(); xmlStaff = xmlDom.CreateElement("person"); xmlPid = xmlDom.CreateAttribute("pid"); xmlPid.Value = pid; xmlStaff.Attributes.Append(xmlPid); xmlLoc = xmlDom.CreateAttribute("loc"); xmlLoc.Value = loc; xmlStaff.Attributes.Append(xmlLoc); xmlFname = xmlDom.CreateElement("firstnames"); xmlTxt = xmlDom.CreateTextNode(fname); xmlFname.AppendChild(xmlTxt); xmlStaff.AppendChild(xmlFname); xmlSname = xmlDom.CreateElement("surname"); xmlTxt = xmlDom.CreateTextNode(sname); xmlSname.AppendChild(xmlTxt); xmlStaff.AppendChild(xmlSname); xmlTel = xmlDom.CreateElement("telephone"); xmlTxt = xmlDom.CreateTextNode(tel); xmlTel.AppendChild(xmlTxt); xmlStaff.AppendChild(xmlTel); xmlRoot.AppendChild(xmlStaff); } ©return 2015 xmlDom; } University of Greenwich the person id attribute must be a valid token this boilerplate code now builds "pid" and "loc" attributes into the <person> element 28 Service Oriented Architectures for the Web lookupValidXmlDocument() we could consider changing directory.dtd to make these attributes #REQUIRED © 2015 University of Greenwich 29 Service Oriented Architectures for the Web PHP Web Service • Create a similar Web service with PHP • with a different but similar MySQL database SELECT * FROM CartoonCharacters © 2015 University of Greenwich 30 Service Oriented Architectures for the Web searchCC.php this Web service is valid against directory.dtd © 2015 University of Greenwich 31 Service Oriented Architectures for the Web PHP Web Service – searchCC.php <?php header('Content-type: text/xml'); respond with XML mime type accept POST and GET REST if ( isset($_REQUEST['name']) ) { $nq = trim($_REQUEST['name']); if ( preg_match("/[^a-zA-Z0-9 \-']|^$/", $nq) ) die ('<directory/>'); } else { die ('<directory/>'); validate input and protect } against SQL injection require '/home/mkg01/include/studb.php'; $link = mysql_connect($host, $user, $passwd) or die ('<directory><error>'.mysql_error().'</error></directory>'); connect to MySQL mysql_select_db($dbName) or die ('<directory><error>'.mysql_error().'</error></directory>'); with exceptions in $query = 'SELECT ccid, firstname, familyname, phone, studio XML FROM CartoonCharacters WHERE familyname RLIKE "'.$nq.'"'; $result = mysql_query($query, $link) or die ('<directory><error>'.mysql_error().'</error></directory>'); $xmlDom = new DOMDocument(); $xmlDom->appendChild($xmlDom->createElement('directory')); $xmlRoot = $xmlDom->documentElement; instantiate a DOM object with <directory> as root element © 2015 University of Greenwich 32 Service Oriented Architectures for the Web PHP Web Service – searchCC.php if ( mysql_num_rows($result) > 0 ) { if the query returned data then loop over all rows in the result while ( $row = mysql_fetch_assoc($result) ) { $xmlPerson = $xmlDom->createElement('person'); $xmlPid = $xmlDom->CreateAttribute('pid'); $xmlPid->value = 'CC' . $row['ccid']; $xmlPerson->appendChild($xmlPid); $xmlLoc = $xmlDom->CreateAttribute('loc'); $xmlLoc->value = $row['studio']; $xmlPerson->appendChild($xmlLoc); $xmlFname = $xmlDom->createElement('firstnames'); $xmlTxt = $xmlDom->createTextNode($row['firstname']); $xmlFname->appendChild($xmlTxt); $xmlPerson->appendChild($xmlFname); $xmlSname = $xmlDom->createElement('surname'); $xmlTxt = $xmlDom->createTextNode($row['familyname']); $xmlSname->appendChild($xmlTxt); $xmlPerson->appendChild($xmlSname); $xmlTel = $xmlDom->createElement('telephone'); $xmlTxt = $xmlDom->createTextNode($row['phone']); $xmlTel->appendChild($xmlTxt); $xmlPerson->appendChild($xmlTel); $xmlRoot->appendChild($xmlPerson); } } echo $xmlDom->saveXML(); ?> © 2015 this is much the same boilerplate as the previous C# Web method return the DOM object to the client University of Greenwich 33 Service Oriented Architectures for the Web searchCC.php this service works with GET and POST REST but not SOAP the XML has no added whitespace this may prove to be convenient © 2015 University of Greenwich 34 Service Oriented Architectures for the Web XML Schema as DTD – directory.dtd <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE directory SYSTEM "directory.dtd"> <directory> <error>Failed to connect to MySQL</error > </directory> modify the DTD to handle exceptions and require attributes <!ELEMENT directory (person | error)*> <!ELEMENT person (firstnames, surname, telephone)> <!ATTLIST person pid ID #REQUIRED loc CDATA #REQUIRED > <!ELEMENT error (#PCDATA)> <!ELEMENT firstnames (#PCDATA)> <!ELEMENT surname (#PCDATA)> <!ELEMENT telephone (#PCDATA)> © 2015 University of Greenwich 35 Service Oriented Architectures for the Web XML Schema as XSD – directory.xsd <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="directory"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="person"/> <xs:element ref="error"/> </xs:choice> </xs:complexType> </xs:element> much the same <xs:element name="error" type="xs:string"/> schema as the DTD <xs:element name="firstnames" type="xs:string"/> <xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element ref="firstnames"/> <xs:element ref="surname"/> <xs:element ref="telephone"/> </xs:sequence> <xs:attribute name="pid" type="xs:ID" use="required"/> <xs:attribute name="loc" type="xs:string" use="required"/> </xs:complexType> </xs:element> <xs:element name="surname" type="xs:string"/> <xs:element name="telephone" type="xs:short"/> </xs:schema> © 2015 University of Greenwich 36 Service Oriented Architectures for the Web Reading a Web Service • Create a .NET web service that accesses XML from a URL • that URL could itself be a web service • searchCC.php reads a telephone directory from a MySQL database • returns a DOM object • is a RESTful web service • readValidXmlDocument is a .NET Web method that simply forwards a query to searchCC.php • uses an ASP.NET string reader • validates the results against directory.xsd © 2015 University of Greenwich 37 Service Oriented Architectures for the Web .NET XmlReader [WebMethod] public XmlDocument readValidXmlDocument(string surname) configure XmlReaderSettings { XmlReaderSettings xmlRS = new XmlReaderSettings(); xmlRS.ValidationType = ValidationType.Schema; xmlRS.Schemas.Add("", "http://stuweb.cms.gre.ac.uk/~mk05/web/soa/directory.xsd"); string getURL = "http://stuweb.cms.gre.ac.uk/~mk05/web/soa/searchCC.php?name=" + surname; XmlDocument xmlDom = new XmlDocument(); build GET REST string try { XmlReader xmlR = XmlReader.Create(new XmlTextReader(getURL), xmlRS); xmlDom.Load(xmlR); read and validate results from } catch ( Exception e ) the PHP Web service { xmlDom.AppendChild(xmlDom.CreateElement("", "directory", "")); XmlElement xmlRoot = xmlDom.DocumentElement; XmlElement xmlErr = xmlDom.CreateElement("error"); XmlText xmlTxt = xmlDom.CreateTextNode("invalid: " + e.Message); xmlErr.AppendChild(xmlTxt); handle exceptions including xmlRoot.AppendChild(xmlErr); validation failure } return xmlDom; } © 2015 University of Greenwich 38 Service Oriented Architectures for the Web readValidXmlDocument() this data is provided by a PHP Web service from a MySQL table © 2015 University of Greenwich 39 Service Oriented Architectures for the Web readValidXmlDocument() $xmlPerson = $xmlDom->createElement('persons'); alter the PHP so that it returns XML that is not valid against directory.xsd this validation exception is caught and handled © 2015 University of Greenwich 40 Service Oriented Architectures for the Web XML Aggregation • Web services are used to create interfaces to data resources • Using DOM structures we can operate on the data • Data from many sources can be aggregated into a single DOM object • .NET provides alternative programmatic approaches to XML • DataSet • XmlNavigator • XSLT © 2015 University of Greenwich 41 Service Oriented Architectures for the Web lookupValidXmlDocument2() this data is provided by a C# method from a MS SQL Server table this data is provided by a PHP Web service from a MySQL table via a C# method © 2015 University of Greenwich 42 Service Oriented Architectures for the Web XML Aggregation – lookupValidXmlDocument2 instance DOM1 to hold results from lookupValidXmlDocument() [WebMethod] public XmlDocument lookupValidXmlDocument2(string surname) { XmlDocument xmlDom1 = new XmlDocument(); xmlDom1 = lookupValidXmlDocument(surname); XmlDocument xmlDom2 = new XmlDocument(); xmlDom2 = readValidXmlDocument(surname); instance DOM2 to hold results from readValidXmlDocument() foreach (XmlNode xmlNode2 in xmlDom2.DocumentElement.ChildNodes) { XmlNode xmlNode1 = xmlDom1.ImportNode(xmlNode2, true); loop over all xmlDom1.DocumentElement.AppendChild(xmlNode1); nodes in DOM2 } return xmlDom1; } this is only successful because both sources provde valid XML © 2015 University of Greenwich import nodes into DOM1 43 Service Oriented Architectures for the Web XML Aggregation • What if we need to aggregate XML with different schemas? • can't simply import the nodes • DOM programing makes this relatively straightforward • Loop over the nodes in the DOM we wish to import • extract the node content into new nodes that belong to the DOM we are merging into © 2015 University of Greenwich 44 Service Oriented Architectures for the Web XML Aggregation with DOM Programming // Create some pointers XmlElement xmlStaff, xmlEle; XmlText xmlTxt; // Loop over the staff nodes in the second XML document foreach ( XmlNode xmlStaffNode in xmlDom2.DocumentElement.ChildNodes ) { // Create a new staff element xmlStaff = xmlDom1.CreateElement(xmlStaffNode.Name); // Loop over the children of the staff element in the second document foreach ( XmlNode xmlNode in xmlStaffNode.ChildNodes ) { // Create new child elements xmlEle = xmlDom1.CreateElement(xmlNode.Name); xmlTxt = xmlDom1.CreateTextNode(xmlNode.InnerText); xmlEle.AppendChild(xmlTxt); xmlStaff.AppendChild(xmlEle); } // Append the new staff element to the first XML document xmlDom1.DocumentElement.AppendChild(xmlStaff); } © 2015 University of Greenwich 45 Service Oriented Architectures for the Web XML Aggregation using Nginx Server • Our Nginx HTTP server deliberately has no database connection • for educational purposes • Aggregate C# and PHP services to provide a name search spanning both MSSQL Server and MySQL databases • could simply implement a proxy to lookupValidXmlDocument2 • Use PHP to forward a query to the two services and merge the result • brings together much of what we have looked at previously with SOAP and REST consumption of heterogeneous services © 2015 University of Greenwich 46 searchCombined.php <?php header('Content-type: text/xml'); Service Oriented Architectures for the Web start with XML mime header massage inputs if ( isset($_REQUEST['name']) ) { $nq = trim($_REQUEST['name']); if ( preg_match("/[^a-zA-Z0-9 \-']|^$/",$nq) ) die ('<directory/>'); } else { die ('<directory/>'); instance a SOAP clinet and } use it to fill DOM1 $args = array('surname'=>$nq); $client = new SoapClient('http://stuiis.cms.gre.ac.uk/.../stafflist.asmx?WSDL'); $xmls = $client->lookupValidXmlDocument($args)->lookupValidXmlDocumentResult->any; $xmlDom1 = new DOMDocument(); $xmlDom1->loadXML($xmls, LIBXML_NOBLANKS); $url = 'http://stuweb.cms.gre.ac.uk/.../searchCC.php?name='.$nq; $xmlDom2 = new DOMDocument(); $xmlDom2->load($url); load DOM2 directly from a GET URL $xmlRoot1 = $xmlDom1->documentElement; foreach ( $xmlDom2->documentElement->childNodes as $node2 ) { $node1 = $xmlDom1->importNode($node2,true); import DOM2 $xmlRoot1->appendChild($node1); } echo $xmlDom1->saveXML(); ?> return DOM1 to the client nodes into DOM1 Service Oriented Architectures for the Web searchCombined.php this data is provided by a C# Web service from a MS SQL Server table this data is provided by a PHP Web service from a MySQL table via a C# method © 2015 University of Greenwich 48 Service Oriented Architectures for the Web Web Service Driven Web Application • An easy way to use these services to drive a Web application is to apply some XSLT • May be server side or client side processed • Server side is easier to develop © 2015 University of Greenwich 49 Service Oriented Architectures for the Web stafflist.php XSLT has done more than just re-order these © 2015 University of Greenwich 50 Service Oriented Architectures for the Web stafflist.php <?php echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ?> <!DOCTYPE html PUBLIC "//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-gb"> <head><title>Staff List</title></head><body> <h1>Staff List</h1> <form method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>"> sticky form posts <p> back to itself <?php $nq = ( isset($_POST['name']) ) ? $_POST['name'] : ''; ?> <input type="text" name="name" value="<?php echo $nq ?>"/> <input type="submit" /> use searchCombined.php </p><p> to access the services <?php if ( isset($_POST['name']) ) { $url = 'http://stu-nginx.cms.gre.ac.uk/~mk05/soa/searchCombined.php?name='.$nq; $xmlDoc = new DOMDocument(); $xmlDoc->load($url); $xslt = new XSLTProcessor(); $xslDoc = new DOMDocument(); $xslDoc->load('stafflist.xsl', LIBXML_NOCDATA); $xslt->importStylesheet($xslDoc); echo $xslt->transformToXML($xmlDoc); } ?> </p></form></body></html> © 2015 University of Greenwich import XSLT file into XSLTProcessor XSLT process the XML 51 Service Oriented Architectures for the Web SQL Insert Web Service • So far we have been retrieving information from various databases • often we want to insert or modify • Need to take extra care when opening up a database to such potential vulnerability • careful input validation • authentication © 2015 University of Greenwich 52 Service Oriented Architectures for the Web .NET SQL Server Insert Web Service [WebMethod] public string insertRecord(string txtFirstname, string txtSurname, string txtTel, string txtLoc, string txtUname, string txtUpwd) input data { includes authentication credentials bool bool bool bool bool bool bl_fn bl_sn bl_tp bl_lc bl_un bl_up = = = = = = Regex.IsMatch(txtFirstname,"[^a-zA-Z0-9 '-]|^$", RegexOptions.None); Regex.IsMatch(txtSurname,"[^a-zA-Z0-9 '-]|^$", RegexOptions.None); Regex.IsMatch(txtTel,"[^0-9]|^$", RegexOptions.None); !Regex.IsMatch(txtLoc,"^([A-Z]{2})$", RegexOptions.None); Regex.IsMatch(txtUname,"[^a-zA-Z0-9]|^$", RegexOptions.None); Regex.IsMatch(txtUpwd,"[^a-zA-Z0-9]|^$", RegexOptions.None); if ( bl_fn || bl_sn || bl_tp || bl_lc || bl_un || bl_up) { string str_idvf = "Input data validation failure: "; if (bl_fn) str_idvf += txtFirstname + " "; if (bl_sn) str_idvf += txtSurname + " "; if (bl_tp) str_idvf += txtTel + " "; if (bl_lc) str_idvf += txtLoc + " "; if (bl_un) str_idvf += txtUname + " "; if (bl_up) str_idvf += txtUpwd + " "; return str_idvf; } © 2015 University of Greenwich regular expressions filter incoming strings build input validation failure message and return it to the client 53 Service Oriented Architectures for the Web .NET SQL Server Insert Web Service bool bl_unc = !Regex.IsMatch(txtUname,"^([a-z]{6})$", RegexOptions.None); bool bl_upc = !Regex.IsMatch(txtUpwd,"^([a-z]{6})$", RegexOptions.None); if (bl_unc || bl_upc) { this code should be replaced with actual return "Authentication failure"; } else { authentication against stored credentials short tnumber = short.Parse(txtTel); try { string conString = "server=sql-server;integrated security=SSPI;database=mk05"; SqlConnection sqlConn = new SqlConnection(conString); sqlConn.Open(); apostrophes are SqlCommand insertCmd = sqlConn.CreateCommand(); valid characters insertCmd.CommandType = CommandType.Text; string txtSn = txtSurname.Replace("'", "''"); string txtFn = txtFirstname.Replace("'", "''"); insertCmd.CommandText = "INSERT INTO mk05.StaffList(FamilyName, GivenNames, Telephone, Location) VALUES ('" + txtSn + "', '" + txtFn + "', " + tnumber + ", '" + txtLoc + "')"; insertCmd.ExecuteNonQuery(); this is the preferred return value return "Record inserted"; } catch ( Exception e) { return "Insert failure" + e; } } expect exceptions and handle them } © 2015 University of Greenwich 54 Service Oriented Architectures for the Web insertRecord © 2015 University of Greenwich 55 Service Oriented Architectures for the Web Conclusions • It's all so easy • especially when it's RESTful • Visual Studio does most of the work • wish we had VS for PHP • PHPeclipse, Netbeans • These examples show main points • still some problems to be resolved © 2015 University of Greenwich 56 Service Oriented Architectures for the Web Questions? © 2015 University of Greenwich 57