WebService
AJAX
Børre Stenseth
Moduler>Webservices>Survey

Survey

Hva
En enkel webservice for surveys

Vi lager en enkel WebService som skal administrere surveys, enkle spørreundersækelser. Tjenesten er svært enkel og håndterer bare spørsmål med to eller tre mulige svar. Det er enkelt å utvide og generalisere tjenesten. Vi vil ha det slik at surveyen presenterer seg på en vevside og når leseren svarer skal han få direkte melding tilbake på samme sted hvordan svarene så langt fordeler seg. Dette svaret formidles via en AJAX forspørsel, som altså sender leserens svar og returnerer status i undersøkelsen.

Se hvordan webservicen presenterer seg: survey

Du kan teste den herhttp://donau.hiof.no/borres/dn/surveyuser/demo.html

Struktur

survey

Vi skal bygge en struktur som på figuren

Survey Webservice er en komplett Webservice. Vi ønsker ikke å integrere denne i alle de vevsidene som skal bruke den så vi lager en hjelpeside, Survey Provider, som formidler kontakten til tjenesten. Brukersidene, Survey users, kommuniserer med denne hjelpesiden via AJAX-forspørsler. På denne måten oppnår vi at vi på en enkel måte kan vise og administere surveys som en del av en vevside.

For at vi skal kunne bruke AJAX-forspørsler fra vevsider som er plassert på andre domener, har vi laget en proxy som kommuniserer med hjelpesiden. I vårt tilfelle er denne proxyen et Pythonskript som oversetter parameterne i AJAX-forspørselen til parameter i en HTTP/GET-forespørsel og bare formidler kontakten.

Alle disse komponenetene er beskrevet nedenfor.

Webservice

Selve webservicen er altså en komplett webservice med SOAP og WSDSL og det hele. Den presenterer seg slik: http://donau.hiof.no/borres/dn/survey/Service.asmx .

Koden som kjører er slik:

_Service.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Web.Services;
[WebService(Namespace = "http://www.donau.hiof.no/borres/dn/survey")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, 
// using ASP.NET AJAX, uncomment the following line. 
[System.Web.Script.Services.ScriptService]
public class Service : System.Web.Services.WebService
{
    public Service()
    {
        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }
#region data
    private XmlDocument loadData(ref string msg)
    {
        try
        {
            XmlDocument doc = new XmlDocument();
            String filename = HttpContext.Current.Server.MapPath(".").ToString() +
                                 "\\App_Data\\results.xml";
            doc.Load(filename);
            return doc;
        }
        catch (Exception ex)
        {
            msg = ex.Message;
            return null;
        }
    }
    private String saveData(XmlDocument doc)
    {
        try
        {
            String filename = HttpContext.Current.Server.MapPath(".").ToString() +
                                 "\\App_Data\\results.xml";
            XmlWriterSettings xs = new XmlWriterSettings();
            xs.Indent = true;
            XmlWriter xr = XmlWriter.Create(filename, xs);
            doc.Save(xr);
            xr.Close();
            return null;
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }
#endregion data
#region methods
    [WebMethod(Description = "A simple service for handling surveys")]
    public string What()
    {
        return "This is a simple service for handling surveys";
    }
    [WebMethod(Description = "Handle respons and return status")]
    public String doSurvey(String id, String answer)
    {
        try
        {
            // load XML data
            String msg = "";
            XmlDocument doc = loadData(ref msg);
            if (msg.Length > 1)
                throw new Exception(msg);
            String xpath = String.Format("//survey[@id='{0}']", id);
            XmlNodeList list = doc.SelectNodes(xpath);
            if (list.Count != 1)
                throw new Exception("id troubble");
            XmlElement survey = (XmlElement)list[0];
            XmlElement op1 = (XmlElement)survey.GetElementsByTagName("option1")[0];
            XmlElement op2 = (XmlElement)survey.GetElementsByTagName("option2")[0];
            XmlElement op3 = (XmlElement)survey.GetElementsByTagName("option3")[0];
            XmlElement head = (XmlElement)survey.GetElementsByTagName("heading")[0];
            if (answer.CompareTo("1") == 0)
                op1.InnerText = Convert.ToString(Convert.ToUInt32(op1.InnerText)+1);
            else if (answer.CompareTo("2") == 0)
                op2.InnerText = Convert.ToString(Convert.ToUInt32(op2.InnerText)+1);
            else
                op3.InnerText = Convert.ToString(Convert.ToUInt32(op3.InnerText)+1);
            
            // save XML data
            String t = saveData(doc);
            if (t != null)
                throw new Exception(t);
            int a1 = Convert.ToInt32(op1.InnerText);
            int a2 = Convert.ToInt32(op2.InnerText);
            int a3 = Convert.ToInt32(op2.InnerText);
            int p1 = Convert.ToInt32(100.0f * a1 / (a1 + a2+a3));
            int p2 = Convert.ToInt32(100.0f * a2 / (a1 + a2 + a3));
            int p3 = Convert.ToInt32(100.0f * a3 / (a1 + a2 + a3));
            String T = String.Format(@"
<div>{0} har svart slik</div>
<table>", Convert.ToString(a1 + a2 + a3));
            T += String.Format("<tr><td>{0}</td><td>{1}%</td></tr>", 
                op1.GetAttribute("txt"), p1);
            T += String.Format("<tr><td>{0}</td><td>{1}%</td></tr>", 
                op2.GetAttribute("txt"), p2);
            if(op3.GetAttribute("txt").Length >0)
                T += String.Format("<tr><td>{0}</td><td>{1}%</td></tr>", 
                    op3.GetAttribute("txt"), p3);
            T += "</table>";
            return T;
        }
        catch (Exception ex)
        {
            return "error: " + ex.Message;
        }
    }

    [WebMethod(Description = "Establish a new survey")]
    public String SetupSurvey(String heading, 
                              String option1, String option2,String option3)
    {
        try
        {
            // load XML data
            String msg = "";
            XmlDocument doc = loadData(ref msg);
            if (msg.Length > 1)
                throw new Exception(msg);
            // find an id
            XmlElement root = doc.DocumentElement;
            String id =
                Convert.ToString(Convert.ToUInt64(root.GetAttribute("lastid")) + 1);
            XmlElement survey = doc.CreateElement("survey");
            XmlElement op1 = doc.CreateElement("option1");
            XmlElement op2 = doc.CreateElement("option2");
            XmlElement op3 = doc.CreateElement("option3");
            XmlElement head = doc.CreateElement("heading");
            survey.SetAttribute("id", id);
            head.AppendChild(doc.CreateTextNode(heading));
            op1.SetAttribute("txt", option1);
            op1.AppendChild(doc.CreateTextNode("0"));
            op2.SetAttribute("txt", option2);
            op2.AppendChild(doc.CreateTextNode("0"));
            
            op3.SetAttribute("txt", option3);
            op3.AppendChild(doc.CreateTextNode("0"));
            
            survey.AppendChild(head);
            survey.AppendChild(op1);
            survey.AppendChild(op2);
            survey.AppendChild(op3);
            root.AppendChild(survey);
            root.SetAttribute("lastid", id);
            String t = saveData(doc);
            if (t != null)
                throw new Exception(t);
            String radioLine=@"
<div><input type=""radio"" name=""choice{0}"" value=""{2}""/>{1}</div>";
            String T=
                String.Format(@"Copy this code to your webpage, within a form:
<h3>{1}</h3>
<div id=""wrap{0}"">",id,heading);
            T+=String.Format(radioLine, id , option1, "1");
            T += String.Format(radioLine, id, option2, "2");
            if(option3.Length > 0)
                T+=String.Format(radioLine,id,option3,"3");
            T+=String.Format(@"
<div>
<input type=""button"" value=""Stem"" onclick=""showIt('{0}',this.form.choice{0});return false;""/>
</div>",id);
            T+=@"
</div>";
            T = T.Replace("<", "&lt;");
            T = T.Replace(">", "&gt;");
            return "<pre>"+T+"</pre>";
        }
        catch (Exception ex)
        {
            return "survey says: error because: " + ex.Message;
        }
    }
#endregion methods
}

Dataene for hver survey lagres i en enkel XML.fil. Den kan se slik ut: Results.xml

Provider

Vi ønsker ikke å lenke til webservicen i alle vevsider som skal/kan bruke denne denne tjenesten, så vi lager en proxy som handterer AJAX-forespørsler på en slik måte at forspørslene sendes til survey-tjenesten, og svaret formidles tilbake til den som spør.

Koden som kjøres i denne proxyen, surveyprovider, er slik:

_ProviderDefault.aspx.cs

Bruk

En typisk bruksside kan se slik ut:

_UserDefault.aspx

Vi ser at dette eksempelet ikke bruker AJAX-kontrollerne som er tilgjengelige i MS verktøykassa, men den illustrerer hvordan vi kan nå proxyen vår vi AJAX. Javaskriptet som formidler dette er showresult.js, som er basert på prototype [1] :

_showresult.js

Bruk fra et annet domene

Den siden du leser nå ligger på domenet "brage.hiof.no", mens hele mekanismen med survey og surveyprovider ligger på domenet "donau.hiof.no". Vi kan altså ikke få tak i serviceprovider via en AJAX-forspørsel direkte, men vi kan sette opp en kontakt på tvers av domene i et skript, f.eks. et Pythonskript:

_SurveyContact.py

Dersom dette skriptet plasseres på "brage.hiof.no", kan vi nå det fra denne vevsiden med en AJAX-forespørsel. Javascriptet som ordner dette er nøyaktig likt det som brukes ovenfor, men adressen, URL'en, er byttet.

_remoteService.js

Derfor er dette mulig:

Blir det snø 17.mai ?

Ja
Nei
Vet ikke

Ny survey

Å opprette et nytt spørsmål kan styres via samme kanaler som en respons. Fra samme domene som service:

Du kan teste herhttp://donau.hiof.no/borres/dn/surveyuser/setup.aspx

eller fra et annet (dette) domenet:

Heading: *
Option1: *
Option2: *
Option3:

Koden er slik:

<form action="#">
<div id="wrap">
    <div>Heading: <input type="text" size="40" name="header"/><span style="color:red">*</span></div>
    <div>Option1: <input type="text" size="40" name="option1"/><span style="color:red">*</span></div>
    <div>Option2: <input type="text" size="40" name="option2"/><span style="color:red">*</span></div>
    <div>Option3: <input type="text" size="40" name="option3"/> </div>
    <div><input type="button" value="Make it" onclick="makeIt(this.form);return false;"/></div>
</div>
</form>
Referanser
  1. prototype Javascript bibliotekprototypejs.orgwww.prototypejs.org/14-03-2010
  • Webservice survey:
    https://svn.hiof.no/svn/psource/Csharpsites/survey
  • proxy:
    https://svn.hiof.no/svn/psource/Csharpsites/surveyprovider.
  • Bruk fra vevside:
    https://svn.hiof.no/svn/psource/Csharpsites/surveyuser
Vedlikehold

B.Stenseth, mars 2010

(Velkommen) Moduler>Webservices>Survey (Sesjoner)