Write .NET Remoting and WebService objects for embedded systems

This is a description of simple ways to implement Microsoft .NET Remoting and WebService objects on “limited” embedded systems (i.e. no hundreds of kbytes of memory, no Windows or Linux large operating system, no GHz CPU, and so on).

An increasing number of embedded systems exchange information with larger "soft" systems. Microsoft DCOM (older technology for connecting software components) is not realistic in smaller systems without MS Windows etc. Microsoft .NET Framework has (among many other things) support for Remote Procedure Calls (RPC) that replace DCOM - .NET Remoting and WebService. Both these are build upon the open text based protocols HTTP (exchange of the information - the transport) and SOAP/XML (information about the objects - the encoding). It is also possible to configure .NET systems to use other protocols (such as the XML-RPC.NET library replacing SOAP with XML-RPC), including custom solutions, but this possibility is not covered here.

Literature and examples in the field of .NET are almost exclusively focused on how larger "soft" systems in MS Windows environments connect. The text here is instead intended to show how to connect larger "soft" systems with small embedded systems (see figure below).

The code required to process the data generated and needed for call/return using Remote Procedure Call (RPC) with .NET Framework SOAP/XML procedures is quite simple. Basically it is just sending (and receiving) packages like follows (part of "Firmware" in picture above - for a corresponding request, see the "call" (SOAP) example in section Remote Procedure Calls (RPC) using XML below):

      sprintf(sendBuffer,                          "<?xml version=\“1.0\” encoding = \“ISO-8859-1\” ?>\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], "<!-- simple SOAP return of the getWeather method from a weather wWbService -->\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], "<SOAP-ENV:Envelope\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], " xmlns:SOAP-ENV=\"http://..wc3.../soap-envelope/\"\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], " xmlns:xsi=\"http://..wc3.../XMLSchema-instance\"\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], " xmlns:xsd=\"http://..wc3.../XMLSchema\">\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], "    <SOAP-ENV:Body>\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], "        <ns1:getWeatherResponse xmlns:ns1 = \“urn:weatherweb\”\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], "	     SOAP-ENV:encoding-style=\“…soap-encoding\”>\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], "            <return xsi-type=“xsd:string”>Horrible and Wet</return>\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], "        </ns1:getWeatherResponse>\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], "    </SOAP-ENV:Body>\r\n");
      sprintf(&sendBuffer[strlen(sendBuffer)], "</SOAP-ENV:envelope>\r\n");

      write_lan(lanp, sendBuffer, sizeof(sendBuffer));
    
Due to the use of known, simple, readable, and standardised open protocols, it is fully realistic to include interfaces looking like distributed .NET Remoting or WebService objects on systems with limited capabilities. In addition to "impersonating" a .NET interface, such systems also need to have TCP/IP+Ethernet, or a serial port alternatively USB (but this requires more SW at the other end of that link).

Below is first a section describing Remote Procedure Calls (RPC) using XML, then one describing a minimalist implementation of a HTTP server for embedded systems, and finally a section describing minimalist implementations of .NET interfaces for embedded systems (.NET Remoting and WebService). The .NET part also provides basics for distributed objects in .NET, and a sketchy description how they work.


Remote Procedure Calls (RPC) using XML

The basic mechanism of .NET Remoting and WebServices is encoding the call/return using XML, and transporting it using HTTP. Within the world of XML there are three main ways to implement a Remote Procedure Call (RPC) - Simple Object Access Protocol (SOAP), Remote Procedure Call using XML (XML-RPC), and the "upstart" REpresentational State Transfer (REST).

REST relies on HTTP itself for accessing and manipulating objects, remote procedure calling, etc (both transport and encoding), and XML (or possibly something else you like, such as JSON) for additional encoding (when needed). SOAP and XML-RPC are both designed to operate from a single URI with methods being invoked from within the request body. This fails to use URIs as they were designed to be used. A URI is a unique resource on the network and as such, each method in your RPC call should use a unique URI. Using REST this is the case, and depending on your request method, different actions can be invoked. REST uses HTTP as it was designed: if you want to get some data you use a HTTP GET request, if you want to delete a record from a database you use a HTTP DELETE request, and so on. Today many organisations provide REST interfaces: E.g. Twitter, Yahoo, eBay, and Amazon.

The basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods:

Unlike SOAP-based WebServices, there is no "official" standard for RESTful WebServices. This is because REST is an architecture, unlike SOAP, which is a protocol.

Programming for RESTful SOA using XML. E.g. create "Robert" in the object "/users/":

        POST /users HTTP/1.1
        Host: myserver
        Content-Type: application/xml
        ...

        <?xml version="1.0"?>
        <user>
            <name>Robert</name>
        </user>
    
E.g. get the representation of "Robert" in the object "/users/":
        GET /users/Robert HTTP/1.1
        Host: myserver
        Accept: application/xml
        ...
    
XML-RPC is remote procedure calling using HTTP as the transport and XML as the encoding. XML-RPC is designed to be as simple as possible, while allowing complex data structures to be transmitted, processed and returned. Notable quite a few WebServices are implemented with XML-RPC. A typical XML-RPC call might look like follows when its data are transferred over a network (TCP/IP and HTTP encapsulations excluded):
      <?xml version=“1.0” encoding = “ISO-8859-1” ?>
      <!-- simple XML-RPC call of the getWeather method from a weather WebService -->
      <methodCall>
        <methodName>weather.getWeather</methodName>
	<params>
          <param>
            <value><string>Aberdeen AB25</string></value>
          </param>
        </params>
      </methodCall>
    

SOAP is the same general idea as XML-RPC (see above), but more features: Enumerations, Polymorphism (type determined at run time), User defined data (such as named parameters). SOAP XML Documents are also more complex: Use namespaces, Formal "envelope" (Soap Header and Soap Body). Notably Microsoft Remoting and WebServices use SOAP.

A typical SOAP call might look like follows when its data are transferred over a network (TCP/IP and HTTP encapsulations excluded):

      <?xml version=“1.0” encoding = “ISO-8859-1” ?>
      <!-- simple SOAP call of the getWeather method from a weather wWbService -->
      <SOAP-ENV:Envelope
       xmlns:SOAP-ENV="http://..wc3.../soap-envelope/"
       xmlns:xsi="http://..wc3.../XMLSchema-instance"
       xmlns:xsd="http://..wc3.../XMLSchema">
          <SOAP-ENV:Body>
	      <ns1:getWeather xmlns:ns1 = “urn:weatherweb”
	       SOAP-ENV:encoding-style=“http:..w3c..soap-encoding”>
	          <address xsi-type=“xsd:string”>Aberdeen AB25</address>
              </ns1:getWeather>
          </SOAP-ENV:Body>
      </SOAP-ENV:envelope>
    

Look at the content of the SOAP call above. It is a fairly simple and readable text that is send over networks "packaged" in HTTP request-response exchanges (also simple and readable text - see section Minimalist code for HTTP server that follows).


Minimalist code for HTTP server providing “Web pages” etc directly from the server code without file systems etc

A very simple way to implement a HTTP server on a “naked” embedded system (has just an Ethernet controller and a TCP/IP stack), and httpd.c is C-language source for one implementation.

Compression, like "gzip", and secure communication, like "SSL", might be added. There are many such libraries available, but the issue of memory footprint on limited embedded systems only leaves a handful of viable candidates (see section "Examples, code, and articles")

For use of "gzip" compression of a HTTP message body, add the lines "Accept-Encoding: gzip" (telling that this sender will accept "gzip" compressed bodies in HTTP messages returned), and "Content-Encoding: gzip" (telling that the "body" part of this HTTP message is compressed using "gzip"), in the preceeding HTTP message header.

HTTP server

Pseudo-code for a Webserver.
      peer = getpeer_lan(PROTOCOL_TCP, 80);

      while (1) {
        lanp = wait_lan(peer);

        read_lan(lanp, req_buffer, sizeof(req_buffer));

        if (!strcmp(“GET  /status  HTTP/1.0\r\n\r\n”, req_buffer)) {
          resplen = create_response_message(resp_buffer, “Hello World”);

          write_lan(lanp, resp_buffer, resplen);
       }

        close(lanp);
      } 
    

Process a HTTP request for an Excel "object"

Extract from Webserver C-code processing a HTTP request for an Excel “object“ named "http://www.junk.com/logdump.xls" from a client, such as Internet Explorer or Excel (give URL to "File open" dialog).
      ...

      /*
       * Send log object "/logdump.xls" to EXCEL
       */
      if (strncmp("GET /logdump.xls ", tbuf, 17) == 0) {
        /* Create the response message */
        sprintf(response_message, "Dump of log data \t Values\n");
        sprintf(&response_message[strlen(response_message)], "Donald \t 0x4711\n");
        sprintf(&response_message[strlen(response_message)], "Duck \t 17\n");
                                                              
        /* Create response header */
        sprintf(response_header, "HTTP/1.0 200 OK\r\n");
        sprintf(&response_header[strlen(response_header)], "Content-type: application/vnd.ms-excel\r\n");
        sprintf(&response_header[strlen(response_header)], "Content-length: %d\r\n", strlen(response_message));
        sprintf(&response_header[strlen(response_header)], "\r\n");
      }
      ...
    

.NET Remoting and WebServices objects directly from object server code without file systems etc

Typically (but not necessarily) .NET Remoting and WebServices objects interact with their clients by means of HTTP request-response over TCP/IP connections. “WebService objects” are like “Remoting objects”, but also include a standard for how clients get descriptions etc of how to interact with the objects (Web Services Description Language - WSDL, Universal Description Discovery and Integration - UDDI).

Here is an introduction how to “Use .NET interacting with embedded systems - Possibilities with limited resources” (file in PDF format).

When a .NET based application on a Windows system (the Client - see code example below) manipulates a distributed object (deployed on the Server), the .NET Framework on the Client automatically creates and sends a HTTP request package from the Client to the Server.

The body of the HTTP request package generated by the client action holds the actual request to the object in SOAP/XML. Here is an example of a HTTP request package sent from a Client to a Server when the client application calls “obj.getValue()” (the actual request encoded with the "i2:getValue" tag):

When the request is served, the object (i.e. the Server) returns a HTTP response package. The body of this HTTP response package then holds the actual response from the object in SOAP/XML. The .NET Framework on the Client automatically interpretates the response, and updates that client application accordingly. Here is an example of a HTTP response package sent from Server to Client as response to a HTTP request package previously generated by the client application “obj.getValue()” call (the actual response encoded with the "i2:getValueResponse" tag):

Implementing .NET Remoting and WebService on an embedded system means receiving calls, interpretating calls, creating reponses, and returning responses, like the ones above. Compression might be interesting for a resource limited embedded system working with HTML, SOAP, and XML (see "how to" in section "Minimalist code for HTTP server ...". On one hand these are fairly verbose text based protocols (actually use 7 bits out of 8, many repeats, and so on - e.g. "gzip" compresses a 393 bytes SOAP package to 249 bytes, or ca 35% reduction), BUT on the other hand the code neded for performing compression and decompression use significant amounts of memory as well (see section "Examples, code, and articles" for alternatives).

The picture below shows a stripped down C-language implementation for processing the “obj.getValue()” example above:

The Dark horse" for implementing .NET Remoting and WebServices at embedded systems, IF they have ca 256 KBytes of flash and 64 KBytes of RAM, is the .NET Micro Framework (NETMF) Open Source .NET platform for resource-constrained devices. It provides an embedded system with "the whole enchilada" at hand here, and a lot more (including GUI and capability to run C# code).

A "proper" .NET Remoting or WebService server implementation has code that parses and interprets XML and SOAP. This approach costs memory (but not as much as .NET Micro Framework (NETMF) - see above). There are many XML and SOAP libraries available, but the issue of memory footprint on limited embedded systems only leaves a handful of viable candidates (see section "Examples, code, and articles").

A "poor man’s solution" is omitting true parsing of XML and SOAP, and just look for the "mission critical" SOAP/XML tags (like the "strstr()" search call for the "<i2:getValue " string in the “obj.getValue()” server code example picture above) and maybe some additional ones for safety, and then discard the rest. When implementing an .NET Remoting or WebService object, its interface is first coded in C# etc, and run on a .NET capable computer with LAN tapping software or application logging to record the HTTP and SOAP/XML packages actually exchanged for this specific objects interface. The server software is then coded to just interpret the critical parts of the received data according to the recorded HTTP + SOAP/XML request, and to return the recorded HTTP + SOAP/XML response with the critical parts modified with the values wanted.

Brief (for embedded systems "to the point") descriptions of this kind of "poor man’s solution" programming implementing basic servers for .NET Service and WebService objects (Client in CS, Server in C-language, and descriptions of the text actually sent on the LAN) are provided in the sections Remoting and WebServices gfurther down.

For more hands-on coding, go to section "Examples, code, and articles" further down.

Remoting

Client and server CS-code example for a .NET Remoting object, and the data packages actually sent on the LAN when using them (including HTTP), are provided in the document “Embedded .NET Remoting“ (file in PDF format). Notably the programmers and system operators for .NET Remoting objects have to make sure that client and server are using matching interfaces, and proper versions of these.

The C-language source code example remotings.c implements a .NET WebService object "MyRemoteObject.soap" that has the methods "getValue()" and "setValue()".

A fairly comprehensive description of Remoting C# calls, and their corresponding SOAP & HTTP telegrams, are provided in Chapter 13 Remoting of the on-line book "XML Web Services and SOAP".

WebServices

Basically a WebService object works like a Remoting object, but with a slightly different content of the data packages exchanged.

A WebService object can also provide a WSDL interface that returns an XML description of the different methods of the objects, their parameters, etc - i.e. their interfaces. Accessing the URL of a WebService object with a “?wsdl” appended (e.g. for the object "donaldDuck.asmx" at the server "http://www.mcduck.com/" it becomes “http://www.mcduck.com/donaldDuck.asmx?wsdl”) returns its interface description. This makes it possible for programmers to get the information manually (e.g. Internet Explorer), and for tools to retrieve it more or less automatically (e.g. MS Visual Studio). Microsoft also provides a command line tool for retrieving these descriptions and automatically generates proxy classes (source code) for use by your clients accessing the WebService object and its methods (e.g. in a command line window of a PC "C:\>wsdl /language:C# /out:DuckProxyClass.cs http://www.mcduck.com/donaldDuck.asmx?wdsl").

Different alternatives for a client to call a WebService object (GET, POST, etc) are described in the document “Embedded .NET WebService” (file in PDF). It also describes how to write a Web page to generate such calls directly from HTML form tags, and directly in the URL.

The C-language source code example webservices.c implements a .NET Remoting server object "MyWebServiceObject.asmx" that has the "wsdl" query possibility, and the methods "getValue()" and "setValue()". for both GET and POST.

A fairly comprehensive description of WebService C# calls, and their corresponding SOAP & HTTP telegrams, are provided in Chapter 1 Introduction to Web Services of the on-line book "XML Web Services and SOAP".

A simple possibility to study and play with WebServices is using Microsoft IIS on a PC running Windows. A brief description "Setting up IIS etc" is provided here (file in PDF format).


Examples, code, and articles

Here are C and CS source code and executable (PC/Windows) files with working examples from the introduction linked above:


"webmaster" for the domain "karnak" in Sweden ("se")