Beruflich Dokumente
Kultur Dokumente
Gerhard Juen
1.3 Existing remote Service Techniques 11 3.3 A Webservice with Application State 52
1 Introduction
1.1 A simple local Service
A "local service" Calculator offers a method add which adds two integers:
calculator
calculator
client
client
request response request response
response
calculator calculator calculator
proxy skeleton
request
request response
calculator
2) calculator.add(10,20)
3)
carry out
add(10,20)
4) return value 30
5)
1) calculator=new Calculator()
2) calculator.add(10,20)
3) prepare request message
{add,10,20}
6) calculator=new Calculator()
7) calculator.add(10,20)
8) carry out
add(10,20)
9) return value 30
14)
Data packages
-> IP-Adresse (193.175.175.111)
Network IP
Layer (3) Internet-Protocol
Ethernet data packages
-> card (MAC) adress
Link Hardware Interface
Layer (2) (Ethernet-card)
Physical
Transmission Line
Layer (1)
calc.php
RESPONSE
HTTP/1.1 200 OK calculator (server)
RESPONSE
Client machine Server machine
Why HTTP?
• Use of existing webservers,
• Passes most firewalls (uses WWW transport).
Why XML?
• The document includes structure information.
• XML-parsers are available for most programming languages.
• Provides even the representation of binary data (see above).
• Provides the representation of data which should not be parsed by the
XML-parser such as XML or HTML-data (CDATA construct).
B using System.Web.Services;
A
C
B
Namespace principle
Germany.Bocholt.Juen.Gerhard
unique in the world
Where do we find namespaces
• namespace organisation of C# classes:
System.IO
System.Web.Services
;
specialization -->
• package organisation of Java classes
• namespace in XML-documents
Proposed namespaces
For Juen:
com.juen
If necessary with additional qualifiers, such as
com.juen.WebserviceCourse
com.juen.ControlSystemCourse
com.juen.BookShop
For students
de.fh-gelsenkirchen.yourname
fi.cop.yourname …
Remark:
Often you find namespaces which look like web-adresses
e.g. the default namespace selected by the .NET framework:
http://tempuri.org/
Such addresses normally do not lead you anywhere
(and nobody would expect this)
[WebService (Namespace="YourChosenNamespace",
Description="Simple integer calculator")]
public class Calculator
:
We insert two numbers (20 and 30) click the Invoke button and get
RESPONSE
HTTP/1.1 200 OK calculator (server)
RESPONSE
Client machine Server machine
Namespace)
Location: YourVisualStudioProjectsRoot\WebserviceClients
• Press Go
• In the field "Web reference name" enter as name for this reference:
RemoteCalculator
Recommendation: Never choose simply the service’s name (in our case
Calculator) in order to avoid name conflicts between the proxy class name
and the proxy class namespace
ProjectDefaultNamespace.WebReferenceName
automatically generated by VisualStudio.
using System;
using System.Collections.Generic;
using System.Text;
A using CalculatorClient.RemoteCalculator;
B //using OtherRemoteCalculator;
namespace CalculatorClient
{
class Program
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Console.WriteLine(calculator.add(20,30));
}
{
}
A Tells the compiler, to look for classes also in the namespace
CalculatorClient.RemoteCalculator. This concerns the class
Calculator with full name
CalculatorClient.RemoteCalculator.Calculator
B Switching between different Calculators (with the same interface) can
simply be done by substituting the line A by another using line.
Prof. Dr. Gerhard Juen, FB Elektrotechnik Bocholt, FH Gelsenkirchen webservice.doc - 31.01.2006
Webservices with C# 35
Project name
Content of Calculator.RemoteCalculator.Calculator:
namespace CalculatorClient.RemoteCalculator {
:
public class Calculator :
System.Web.Services.Protocols.SoapHttpClientProtocol
{
public Calculator() {
A this.Url = global::
CalculatorClient.Properties.Settings.Default.
CalculatorClient_RemoteCalculator_Calculator;
}
B public int add(int i1, int i2) {
object[] results = this.Invoke(
"add", new object[] {i1, i2});
return ((int)(results[0]));
}
}
}
("http://127.0.0.1/WebServices/Calculator.asmx")]
B As expected, the proxy’s add method has the same signature as the
original local service call (i.e. the Calculator’s add method).
Internet
Intranet Internet
direct direct
Webservice communication HTTP communication Webservice
client proxy server
Local IP-adress Local IP-adress Public IP-adress Public IP-adress
192.168.60.111 192.168.60.68 80.15.75.141 193.175.175.141
Typical situation:
• Webservice client runs within a local Intranet
(all PC's have only local IP-addresses)
• The public webservice in the internet you are interested in
is not directly accessible
(no direct connection between local and public IP-addresses possible)
<configuration>
<system.net>
<defaultProxy>
A <proxy usesystemdefault="true"/>
</defaultProxy>
</system.net>
<configuration>
Substitute line A by
<proxy usesystemdefault="false"
proxyaddress="http://127.0.0.1:3128"
bypassonlocal="true"
/>
2.11 Exceptions
In case of a local method call you might get s.th. similar to:
A using System.Web.Services.Protocols
:
:
if (i1<0) throw new SoapException(
B "i1<0 not allowed",
C SoapException.ClientFaultCode);
A this line includes the namespace System.Web.Services.Protocols
to which the SoapException class belongs.
B The first parameter defines our error text
C The second parameter allows to classify the error:
SoapException.ClientFaultCode
means that the error has been caused by wrong request parameters,
i.e. the client should modify the request and then try it again.
SoapException.ServerFaultCode
means that the fault has been caused by some server related
condition, e.g. by a inactive server database. In this case the client
should come back later.
The client side message (e.Message) reads
i1<0 not allowed
2.12 Excercises
2.12.1 Integer Calculator
• Extend the Calculator webservice with a two integer subtract, multiply and
divide method.
• Check this webservice with a browser.
• Extend the existing C# test client.
• Check what happens if you call calculator.div(10,0).
• Include your own error handling in the div method:
- Throw a Soap-Exception in the calculator server in case of the second
parameter equal to zero.
- Catch this error in the Client
Hint:
If you change the webservice “interface” you have to update the web reference
at client side in order to get an actual version of the service proxy.
Change the interface means one of the following:
• you modify the signature of an existing webmethod
• you delete an existing webmethod
• you include a new webmethod
Prof. Dr. Gerhard Juen, FB Elektrotechnik Bocholt, FH Gelsenkirchen webservice.doc - 31.01.2006
Webservices with C# 47
Hint:
All „float“ variables should be declared as float.
2.12.3 SMS-Provider
Develop a client for the SMS-Provider service with the WSDL
http://193.175.197.65:8080/Sms.jws?wsdl
Try to find out which parameters the not commented send method expects.
3 Stateless/statefull Webservice
3.1 Stateless Webservice
So far all our webservices implement a stateless "remote procedure call". Each call
• creates on the server its own service object
• executes the service (calls the remote method) and
• destroys the service object afterwards.
Subsequent calls never see the same object. Consequence: You cannot store
information in the service object which is passed through the sequence of calls.
This is the reason to classify webservice/soap as remote procedure call technique
instead of remote object technique.
Example “Accumulator”:
The webservice provides an integer accumulator which can be resetted and
incremented from remote. The increment call carries out the increment and
returns the accumulator content.
Server
<%@ WebService Language="C#" class="Accumulator" %>
using System.Web.Services;
[WebService(Namespace="com.juen")]
A public class Accumulator : WebService
{
[WebMethod]
public void reset() {
Application["accValue"]=0;
}
[WebMethod]
public int increment (int inc) {
B int accValue=inc;
C if (Application["accValue"]!=null) {
D accValue+= (int) Application["accValue"];
}
E Application["accValue"]=accValue;
return accValue;
}
}
A Our service class is derived from the class WebService from which we
use the property Application. Application is a “container” for
objects. An object put into the container exsist as long as the application
server is running. Furthermore, all these objects are global in the sense
that they can be read and written in all server side Accumulator
instances.
D..E The application variables stored in Application can be elementary data
types such as integers as well as references to complex objects.
In our application we store a simple integer i.e. accValue.
Each application variable is addressed via a freely chosen keyword
Application["some_explaining_keyword"]
in our case
Application["accValue"]
D As Application["..."] may store references to arbitrary objects we
have to cast the value returned by the read operation to the data type we
expect, i.e. int in our case because we know that we have put an int
into the container.
Lifetime
The session state is cleared when the client program ends.
3.5 Exercise
• Develop a webservice SimpleChat (server + client) with 4 methods
public void setPrivateText(string text);
public string getPrivateText();
public void setPublicText(string text);
public string getPublicText();
The transferred text is stored as session (private) or application (public)
variable.
• Act with two clients against this service and show that
the private text really remains private and that
the public text is really public.
• Show by experiments that
session variables are deleted on client task exit and
application variables are not deleted on client task exit.
sender receiver
serialising deserialising
(marshalling) (unmarshalling)
bytestream
linear byte linear byte
sequence transport sequence
A D H
B C E
F G
Possible serialisation:
A B C D E F G H (or reverse)
A D H B C E F G (or reverse)
A B C D H E F G (or reverse)
:
Questions:
Which one to take?
How to tell the remote partner about my choice? ..
Prof. Dr. Gerhard Juen, FB Elektrotechnik Bocholt, FH Gelsenkirchen webservice.doc - 31.01.2006
Webservices with C# 63
"Serialise y" => serialise y, a "pointer to float" ? => Does not make sense
serialise the float to which y points? => Makes sense
serialise 100 float ? => might make sense if
there was an
instruction y=x;
somewhere before
"Serialise x" => serialise a single float ? => Does not make sense
serialise 100 float ? => Makes sense
But: in C x is nothing else than a pointer to float (the first float of the array). I.e.
in the final executable there does not exist any information on how many floats
the pointer x really points to. In other words: x looks syntactically like y.
Prof. Dr. Gerhard Juen, FB Elektrotechnik Bocholt, FH Gelsenkirchen webservice.doc - 31.01.2006
Webservices with C# 65
Problem 6:
All problems 1 .. 5 have to be solved for each possible pair of different
communication endpoint technologies.
sender receiver
machine 1 data machine 2 data
representation representation
serialising deserialising
(marshalling) (unmarshalling)
standardised
translation translation
English
English English
transport
NDR Examples
network data represen- Programming
Technique Explanation
tation Language
Remote Method Java object serialisation
RMI Java only
Invocation technique (name?)
Common Object Request CDR (Common Data Re-
CORBA Many
Broker Architecture presentation)
XDR (External Data Re-
ONC-RPC ... Remote Procedure Call C (Java)
presentation)
DCE-RPC ... Remote Procedure Call C++, Visual
NDR2) (Network Data Re-
Distributed Component Basic, Object
DCOM presentation)
Object Model 1) Pascal (Delphi)
Simple Object Access
SOAP SOAP Encoding Many
Protocol
1) Object oriented add on for DCE-RPC
2) Here the term NDR ("Network Data Representation") is the name of one of the
NDR standards.
Service example
Receives an array of integers and returns the sum.
The server
We simply extend the Calculator service with a method addArray:
[WebMethod]
public int addArray (int[] arr)
{
int sum=0;
for (int i=1;i<arr.GetLength(0);i++)
sum+=arr[i];
return sum;
}
}
The client
:
class Calculator
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
// The already existing test cases
:
:
int[] arr={11, 22, 33, 44};
Console.WriteLine(calculator.addArray(arr));
}
}
4.3 Exercise
a) Extend your FloatCalculator with a webmethod scalarProduct which
receives two arrays of float, interprets them as 2 vectors and returns the scalar
product. If the two arrays do not contain the same number of entries a
SoapException “Different lengths of the two arrays not allowed” is thrown.
The client should catch SoapException type exceptions.
b) Extend your FloatCalculator with a webmethod sumVector which
receives two arrays of float, interprets them as 2 vectors and returns the sum
vector. Exception handling is as in a).
c) Extend your FloatCalculator with a webmethod scalarProduct which
multiplies a float array by a scalar number.
IntNode
int nextNode
int nextNode
int nextNode
int null
IntNode
The server
<%@ WebService Language="C#" class="IntList"%>
using System.Web.Services;
[WebService(Namespace="com.juen")]
C public class IntList {
[WebMethod]
D public int add (IntNode startNode) {
int sum = 0;
E while (startNode!=null) { // while not last node
sum+=startNode.i;
startNode=startNode.nextNode; // go to next node
F }
return sum; // sum over all nodes
G }
}
A..B The class IntNode defines the nodes of the "chained integers list". It
contains the integer i and the reference nextNode to the next node.
D..G This is the method add of the IntList webservice. It is called with the
reference of the first (root) node of the "chained list of integers".
E..F The main loop of the add method walks through the list, adds all the
integer numbers of the nodes and stops at the last node.
The client
Remark: This example is not to demonstrate good modelling but shows only the
automated serialisation/deserialisation of a chained list.
using System;
class IntListClient
{
static void Main(string[] args) {
IntNode intNode1 = new IntNode();
IntNode intNode2 = new IntNode();
IntNode intNode3 = new IntNode();
// create chained list: intNode1->intNode2->intNode3
intNode1.nextNode=intNode2;
intNode2.nextNode=intNode3;
intNode3.nextNode=null;
// fill the data into the nodes
intNode1.i=11;
intNode2.i=22;
intNode3.i=33;
// Create service proxy and call the service
IntList myIntList=new IntList();
Console.WriteLine(myIntList.add(intNode1));
}
}
Consequence 1:
(Complex) data can only be returned through the return value.
Consequence 2:
If more than one data structure/object needs to be sent back all these data
structures/objects have to be packed into an appropriate "return"-object.
4.6 Complex return Value
Webservice IntList: (from above)
Webmethod scalarMult Receives a list of integers and s scalar returns the set
of integers with each integer multiplied by the scalar
Webmethod (server) , which assumes call by reference => does not work
public void scalarMult (IntNode startNode, int fak)
:
while (startNode!=null) { // while not last node
startNode.i=fak* startNode.i; // multiply by fak and
startNode=startNode.nextNode; // go to next node
}
:
// display result
Console.WriteLine(intNode1.i); // you see 11, not 22
Console.WriteLine(intNode2.i); // you see 22, not 44
Console.WriteLine(intNode3.i); // you see 33, not 66
:
// display result
while (ret!=null) { // while not last node
Console.WriteLine(ret.i);
ret = ret.nextNode;
}
4.7 Exercise
4.7.1 The extended Finnish German translator
The Finnish German translator (Finger) methods provide two kinds of result
• Finnish or German word only
• Finnish or German word + additional English translation
Modify your Finger client such that it calls the methods ger2fin2eng and
fin2ger2eng which also deliver the English translation.
4.7.2 Simple News System
a) Develop a webservice which receives text-messages from clients and stores
them into a chained list. Each client should have access to all messages. The
service provides two methods:
public void addMessage(string messsage)
public StringCollection getMessages()
b) Extend the service with a login/logout mechanism:
public bool login(string password)
public void logout()
For simplicity we use only one password for all, i.e. YLIVIESKA . Use session
state for tracking the "login status" of the individual clients. A client request of a
method from a) should throw an Exception, if the client is not in login-status.
Prof. Dr. Gerhard Juen, FB Elektrotechnik Bocholt, FH Gelsenkirchen webservice.doc - 31.01.2006
Webservices with C# 83
Hello
I am Peter
Nice to meet you
What shall we do today
I am Peter
Nice to meet you
5 Soap Protocol
5.1 Webservice with Transport Sniffer
If we want to observe the data stream on the HTTP transport level we can
• use some network sniffer software or
• include a "sniffer" into the data stream either at server or at client side.
Currently .NET does not provide a debugging feature such as "look at the
transport" and we have to develop it by ourselves (I did it for you).
How to add client side HTTP level logfile support (calculator example)
• Load webserviceutilities.dll from juen's website and add it as
project reference.
• Add the line using Juen.WebserviceUtilities to the calculator proxy
class file Calculator.cs.
• Add the bold line before each method for which you want to have logfile
support:
using Juen.WebserviceUtilities;
:
[SoapLog (Filename="c:\\tmp\\soap.log")]
public int add(int i1, int i2)
{
:
}
• Attention: each time you refresh the web reference you generate a new proxy
class where these added lines no longer exist.
How to add server side HTTP level logfile support (Calculator server example)
• Add the line using Juen.WebserviceUtilities to the class file
Calculator.cs.
• Add a similar bold line as in the client case before each method for which you
want to have logfile support.
• Copy webserviceutilities.dll into the "application-bin" directory of the
Webservice related IIS-application (see chapter 3).
Request-message
A <?xml version="1.0" encoding="utf-8"?>
B <soap:Envelope
C xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
D xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
E xmlns:xsd="http://www.w3.org/2001/XMLSchema">
F <soap:Body>
G <add xmlns="http://juen.com/webservices/">
H <i1>-20</i1>
I <i2>30</i2>
J </add>
K </soap:Body>
L </soap:Envelope>
C..D Defines all the namespaces for the standard elements. Standard elements
come from the “Soap world”, line C, and from the “XML-Schema world”,
line D and E. XML-Schema elements are not used here.
F..K The Body element contains the data related to our request. An optional
Head element allows to transport meta information.
G..J The elements add, i1 and i2 are defined by our application. The
corresponding namespace has been defined in the [WebService..] line
of the webservice asmx-file.
Response-message
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<addResponse xmlns="http://juen.com/webservices/">
<addResult>10</addResult>
</addResponse>
</soap:Body>
</soap:Envelope>
Definition of the "address" where the service waits for the clients
<service>
:
</definitions>
Namespaces:
<definitions
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:s0="http://juen.com/webservices/"
xmlns:soapenc="http://schemas.xmlsoap.org/
soap/encoding/"
xmlns:tm="http://microsoft.com/wsdl/
mime/textMatching/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://juen.com/webservices/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
:
</definitions>
The root element defines all the used namespaces.
xmlns:s="http://www.w3.org/2001/XMLSchema"
means e.g. that a subsequent element marked with a prefix s such as
<s:complexType>
are defined in the namespace
http://www.w3.org/2001/XMLSchema
Data types
<types>
<s:schema
elementFormDefault="qualified"
targetNamespace="http://juen.com/webservices/">
here comes one element per data type
</s:schema>
</types>
B <s:element name="addResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="addResult" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
A defines a data type add, which will later be used in the add request
message
B defines a data type addResponse, which will later be used in the add
response message
B <message name="addSoapOut">
<part name="parameters" element="s0:addResponse" />
</message>
A defines a message addSoapIn which transports a parameter of data
type add, which has been defined in the <types> section. This
message will later be used as "request message" of the add webmethod.
B defines a message addSoapOut which transports a parameter of data
type addResponse, which has been defined in the <types> section.
This message will later be used as "response message" of the add
webmethod.
B <operation name="add">
<soap:operation
soapAction="http://juen.com/webservices/add"
style="document"
/>
<input><soap:body use="literal" /></input>
<output><soap:body use="literal" /></output>
</operation>
</binding>
A specifies HTTP as transport layer.
B specifies transport specific details for each webmethod.
Web Service
has has has
method
<operation>
refers to refers to
request response
<bold> message message
means top level element <message> <message>
>refers to > refers to
Defined in request data response data
<types> type type
<element> <element>
> >
Prof. Dr. Gerhard Juen, FB Elektrotechnik Bocholt, FH Gelsenkirchen webservice.doc - 31.01.2006
Webservices with C# 99
6 Asynchronous Webservice
6.1 Blocking vs. non Blocking Call
client server
add_request
process the
result
add_request
non blocking call
Beginadd(10,20)
process
add(10,20)
add_response
do s.th. useful
Get result:
sum=Endadd
We go back to the simple calculator with method add and look into three methods
of the generated client side proxy class Calculator.
namespace CalculatorClientWithCallback
{
public class Program {
bool cont=true; // loop while cont ==true
Calculator calculator; // the service proxy
// "main" method
void run() ..
// "main" method
void run()
{
calculator = new Calculator();
// asynchronous call
A calculator.BeginaddWithDelay(
10, 20, // numbers to add
B new AsyncCallback(showResult), // wrapped callback
C null // object feed through not used here
);
int counter=0; // "while loop" counter
D while (cont)
Console.WriteLine("Counter = "+counter++);
}
using System.Threading;
:
public class Calculator
{
[WebMethod (Description="Adds two numbers")]
public int add (int i1, int i2)
{
// 10 s delay
Thread.Sleep(new System.TimeSpan(100000000));
return i1+i2;
}
:
}
6.3 Exercise
Develop a webservice which fetches the content of a remote text file. Develop a
GUI-client which calls this service asynchronously and uses the callback method to
store the received data to the local file system. The name of the remote file and the
full path name where to store it are entered on the screen. Try to use the object
pass through mechanism to transport the local filename to the callback routine.
Remark: The following example shows a program which writes the content of a text
file to the screen.
class TextFileDemo {
try {
fs = new FileStream
(@"c:\tmp\test.txt",FileMode.Open,FileAccess.Read);
StreamReader sr = new StreamReader(fs);
string content = sr.ReadToEnd();
Console.Write(content);
fs.Close();
}
catch (Exception e) {
Console.WriteLine("Cannot read from file "+ file);
}
}
}
7 Architectures
7.1 Software Interface for Web Site
Architecture:
Internet
NameValueCollection postValues =
new NameValueCollection(6);
postValues.Add("from", from);
postValues.Add("to", to);
postValues.Add("keyb", "non");
postValues.Add("text", toTranslate);
Prof. Dr. Gerhard Juen, FB Elektrotechnik Bocholt, FH Gelsenkirchen webservice.doc - 31.01.2006
Webservices with C# 113
postValues.Add("Submit.x", "47");
postValues.Add("Submit.y", "13");
string uristring=
"http://www.tranexp.com:2000/Translate/result.shtml";
byte[] bodyData = webClient.UploadValues
(uristring, "POST", postValues);
string s = Encoding.Default.GetString(bodyData);
if (s.IndexOf("Could not open")>0)
{
ret.translation=
"Dictionary temporarily not available";
ret.english="";
return ret;
}
Example:
The SMS-service -> Java Axis
webportal
"My City" own
content
weather report
webservice