.NET Remoting and Web Services: A Lightweight
Bridge between the .NET Compact and Full Framework
Bert Vanhooff, Davy Preuveneers and Yolande Berbers, K.U.
Leuven, Department of Computer Science, Belgium
|
 |
ARTICLE

PDF Version |
Abstract
With the growing popularity of powerful connected mobile devices (PDAs,
smart phones, etc.), an opportunity to extend existing distributed applications
with mobile clients emerges. The Microsoft .NET Compact Framework offers
a development platform for mobile applications but is lacking support
for .NET Remoting, which is the .NET middleware infrastructure for inter-application
communication. The current version of the .NET Compact Framework (1.0,
SP2) does support communication using web services. Unfortunately this
support cannot be used in its current form to seamlessly integrate with
an existing .NET Remoting application. In this paper, we propose an
approach that leverages the present support for web services and augments
it to make such integration possible. Our solution dynamically maps
back and forth between .NET Remoting and web service messages without
needing to alter the existing Remoting applications.
1 INTRODUCTION
.NET is a Microsoft brand name that encompasses a whole array of technologies.
A few key terms associated with this brand name are connected systems,
smart devices and web centric computing. These terms could be categorized
under the more general denominator of distributed systems. In short,
.NET offers a complete package of tools and technologies for developing
applications, especially targeted towards distributed systems.
The most important part of .NET is the .NET Framework [Mic], which
consists of an execution environment for applications and a comprehensive
class library. The framework includes .NET Remoting [Mcl03] in order
to support the development of distributed applications. This is an
extensible Distributed Object Computing (DOC) middleware infrastructure
comparable to the Java Remote Method Invocation (RMI) [Sun] although
the latter adopts an entirely different internal architecture.
The .NET Compact Framework [Wig03] is a slimmed down version of the
.NET Full Framework made to run on embedded devices such as PDAs and smart
phones. To take into account the resource limitations
of these
devices, a dedicated execution environment was crafted and some
classes and methods of the standard .NET class library were removed.
.NET
Remoting was among those removed namespaces. As Remoting cannot
be used on the
.NET Compact Framework, a communication barrier exists between
the .NET Full Framework and the .NET Compact Framework (Figure 1).

Figure 1 The .NET Remoting barrier between the .NET
Full and Compact Framework
The absence of .NET Remoting in the .NET Compact Framework puts some
serious constraints on the development of connected smart clients.
Recently, advanced and Wifi-enabled PDAs and smart phones have created
the need to extend existing distributed applications to incorporate
these smart clients. However, the lack of support for .NET Remoting
on these devices makes it hard to integrate them into legacy systems,
often build with that technology (Figure 1). In this paper we propose
a mechanism that enables smart clients running the .NET Compact Framework
to access these Remoting objects to a certain extent, with little overhead
for the programmer and little changes to be made to the existing part
of the distributed application. Our approach focuses on client/server
architectures: the server is not aware of any objects on the client,
while the client can see and access objects on the server. Our solution
uses .NET Remoting’s built-in extension support (on the server)
and a custom extension to the existing web services support on the
client.
In the next section, .NET Remoting and web services are discussed in
detail and a list of requirements for our solution is presented. In
section 3 we explain the concepts that solve the basic requirements.
These concepts are then used as the foundation to solve other requirements
(section 4). We discuss our implementation of the basic concepts and
some practical results in section 5. Finally we present some related
work (section 6) and we round up the paper by drawing conclusions,
summarizing the strengths and weaknesses of our solution and giving
suggestions for future improvement (section 7).
2 DISTRIBUTED APPLICATIONS IN .NET
The .NET Framework offers .NET Remoting and web services as high-level
technologies for developing distributed systems. This section introduces
the parts of these technologies that are relevant for the rest
of the paper and it points out the constraints involved when using
web services
instead of .NET Remoting. We conclude this section by giving a
minimum set of requirements for a useful solution.

Figure 2 Channel sinks and IMessages in the Remoting
infrastructure.
.NET Remoting
.NET Remoting simplifies the development of distributed systems by
offering an extensible infrastructure that permits objects that do
not reside in the same memory space (or even on the same host) to
communicate with one another in a transparent fashion. This implies
that every message sent to a remote object will have to be delivered
through an alternative (non-local) mechanism. Therefore, each message
from a local (client) object to a remote (server) object will be
intercepted using a (double) proxy pattern. A message, which can
for example represent a method or constructor call, will be transformed
into a Remoting message-object. Such a message object implements
the IMessage interface (we will refer to these types of objects as
IMessage objects) and contains all the necessary information needed
to reconstruct the original call. IMessage objects are created and
inserted into the Remoting infrastructure by the proxies. A graphical
representation of the relevant parts of the Remoting infrastructure
is shown in Figure 2. We elaborate on these parts in the next few
paragraphs.
After passing through the proxies, an IMessage object is further
propagated through the .NET Remoting infrastructure. This part contains
several
so called sink chains, which are series of concatenated sink objects,
each given the opportunity to modify the IMessage object as in a pipe-and-filter architecture. The sink chains provide the main extension mechanism
by enabling the insertion of your own custom sink objects. Some sink
objects are provided by default, including a formatter sink that serializes
IMessage data and a transport sink that takes care of physical message
transportation. Sink chains that contain these two types of sinks are
located at the end of the Remoting infrastructure and are called channels.
Channels are the first components in the .NET Remoting infrastructure
that get to see all incoming messages and the last to see all outgoing
messages. Sink chains that do not belong to a channel only get to see
specific categories of IMessages. For example a sink in the server
object sink chain, only gets to see IMessages originating from one
specific object.
Figure 2 shows the possible flow of an IMessage through the sinks
in a channel when both client and server are using .NET Remoting. An
IMessage is created in the proxies (top-left of the figure) on the client and
travels through the infrastructure (full lines) until it arrives at
the first Custom Channel Sink, which is a specialized version of a
message sink. Each custom sink shown in the figure actually represents
either one custom message sink or a subchain of custom message sinks
(only one is shown due to space considerations). The IMessage then
moves further to the Client Formatter Sink, where it is serialized.
After that, the message passes another series of Custom Channel
Sinks to finally end in the Client Transport Sink. This last sink physically
sends the message to the server using some kind of network technology.
When the message is received at the server (right part in the figure),
an equivalent chain of sinks is passed on the server until the call
to the actual object can be executed. A response will, in turn, be
represented by an IMessage that travels in the opposite direction (dotted
lines).
To summarize, Proxies, IMessages and Custom Sinks are three important
elements that provide for the extensibility of .NET Remoting. Using
one or more of these extension elements we can add, for example, encryption
or logging facilities to the standard .NET Remoting functionality.
A more exotic extension could be one that provides a new serialization
mechanism. Later on in this paper we will use a Custom Channel
Sink that manipulates IMessages.
Web Services
In general, “web services” refer to all techniques that
enable applications to offer their services to one another over a network
by means of Internet technologies. In this paper, we use the more restricted
interpretation of [W3c02, Boo03]: SOAP over HTTP and WSDL. SOAP (Simple
Object Access Protocol) [Box00] is an XML based protocol for the messages
sent by a web service, while WSDL (Web Service Description Language)
[W3c03] is an XML language used to describe the interface offered by
such a service. The use of these protocols is fully supported in the
.NET Compact Framework.
An important characteristic of web services is that they have a document-oriented
(or, in RPC mode, a simple procedure-oriented) architecture instead
of an object oriented architecture. They do not support an object
reference-model; all data in a document is passed by value. This prevents
us from directly
using web services to interoperate with .NET Remoting because exchanging
documents is totally different from typical object oriented operations
such as instantiating new objects, invoking methods on objects, passing
object references, navigating object graphs, etc. Such operations
are typically supported by DOC (Distributed Object Computing) middleware
such as .NET Remoting, CORBA and Java RMI.

Figure 3 A Remote object published as a web service
through the Remoting infrastructure.
One of the features of Remoting (that can be quite confusing), is
its direct support for offering remote objects as if they were web
services, through its own infrastructure. Individual remote objects
can easily be published and accessed – in a very limited way – using
web services (see Figure 3). When accessing a remote object through
a web service in Remoting, the client can only call methods that return
primitive or structured data types due to the lack of a reference-model.
As a consequence, he cannot get outside the scope of the initial object
by navigating the object graph because any method call, which would
normally return a reference to an associated object, will now only
return the data contained in the associated object (non-recursive)
and not the object reference itself. One of the advantages of offering
web services through .NET Remoting is that we can use its comprehensive
extension mechanisms for handling web service requests. However, some
functionality will be lost due to the inherent limitations of standard
web services [Alm01].
In its current implementation, accessing remote objects through web
services requires that the objects are (1) published on well-known
URLs in advance and (2), that they are not removed during the application’s
lifetime in order to prevent calls to dead objects. Objects that are
created during the operation of the system will not be accessible.
Consequently, an application offered as a set of web services must
have a static object graph (at least for the published objects) and
may not delete any of the published objects since this would result
in unanticipated access faults. In addition, newly created objects
cannot be directly accessed by web service clients. Note, however,
that data present in newly created objects could be accessed indirectly
through methods from another object that is published as a web service.
A web service is generally accessed using a proxy in order to provide
for some transparency and to keep the programmer from having to do
a lot of cumbersome coding. There are standard tools available to generate
these proxies for a remote object directly or using a WSDL description.
Direct generation is only applicable if an object is published as a
web service by the Remoting infrastructure. Whenever the tools encounter
a method that returns or accepts an object, this object will be mapped
to a complex SOAP data structure, removing some of the object’s
richness in the process. Consequently, from the point of view of these
proxies the very notion of an object disappears. Additionally the notion
of event notification is not present in the basic web service architecture,
so this functionality also disappears in the WSDL.
The web service limitations, along with the dynamic nature of most
object graphs, make the web service support provided by .NET Remoting
inadequate for developing smart clients with the same capabilities
as full Remoting clients. This becomes an even greater issue when extending
an existing Remoting application if the application was not originally
designed with this puprose in mind. The focus of this paper is on extending
such applications.
Requirements for Crossing the .NET Compact / Full Framework Boundary
We described that the lack of .NET Remoting on the .NET Compact Framework
creates a communication boundary between the .NET Compact and Full
Framework. Using the standard ability of both frameworks to consume
(and offer, in case of the Full Framework) web services does not offer
an adequate solution to cross that boundary. Therefore we have to figure
out an alternative approach for interacting with remote objects that
is able to offer many of the .NET Remoting advantages, without having
to port the full Remoting infrastructure to the .NET Compact framework.
A concrete list of the requirements we expect a good solution to meet
is given here:
Functionality
- Make the object graph on the server navigable from the client
and enable the client to refer to a specific object on the server;
- enable method calls on remote objects (with object references
both as parameters and as return type);
- enable callbacks (event occurrences) from the server to the
client;
Development support
- enable fast client development by hiding communication details
from the programmer, generally minimize the programmer’s overhead;
- minimize the impact on existing applications.
We will show in the next sections that these requirements can be
fulfilled by reusing large parts of the readily available infrastructure
(and
its extension mechanisms) and extending them on both the client
and the server platform. Leveraging the existing infrastructure significantly
shortened the development time of our solution.
3 USING TWO WEB SERVICE ABSTRACTION LAYERS TO ACCESS REMOTE OBJECTS
In this section we explain our approach to make remote objects
available to clients running the .NET Compact Framework, or
more generally
to clients supporting web services. We start by describing
the basic approach
and continue by discussing some extensions that are build on
this foundation.
Basic Approach
As already discussed, .NET Remoting can publish a degenerate
version of the public interface of a remote object (no
object references,
no events, etc.) through a web service on a known URL.
We will extend this basic capability with an extra layer of abstraction
in order
to
overcome the inherent limitations. Figure 4 shows how we
accomplish
our goal at a highly abstract conceptual level. We will
introduce
two web service abstraction layers that hide communication
details from
the programmer and enable object-oriented-like communications
over a web service link. The abstraction layer at the server
side will
make use of a Remoting extension and the Remoting support
for offering web
services, while the one at the smart device client will
make use of custom generated proxies and the existing web service
support
of the
.NET Compact Framework.

Figure 4 Web service abstraction layers.
The main reason we still like to use web services to build our solution,
in spite of the mismatch between .NET Remoting and web services is
twofold. First of all the support for web services in the .NET Compact
Framework provides us with high-level and easier to use communication
primitives compared to plain sockets for example. Web services provide
an RPC-style of communication and a common network representation of
data. Secondly, since Remoting supports processing web service requests
through its infrastructure, the modifications on the server can be
better contained and are less intrusive on existing applications. These
choices also ease the development effort of the abstraction layers
themselves because we can use large parts of the existing infrastructure.
A possible disadvantage is that we trap ourselves in the limitations
of web services, hampering development with the search for workarounds.
We will show that this was not the case.

Figure 5 Basic operation of the web service abstraction
layers. The idea behind our solution is to dynamically
publish a remote object as a web service whenever a web service client
invokes an operation which returns a reference to that object. An object
reference can then be uniquely mapped to a web service URL, which also
functions as a globally unique identifier and locator for our server
objects. Whenever an object reference is required we substitute it
by the URL of the object’s corresponding web service. Figure
5 demonstrates the idea by an example scenario. We start from an existing
application consisting of a graph of three interconnected objects,
objA, objB and objC. The starting object objA will be accessible – through
a proxy – using a web service on a well-known URL (1). By invoking
methods on this object, we can navigate to the other objects in the
graph as follows. Whenever the client calls a method that returns a
reference to another object (not transportable using standard web services),
that object will be exposed through a web service. The URL to reach
this service will instead be returned to the client as a substitute
for the real object reference. Using this URL, the client can access
the new object (2) using a corresponding proxy. In this way every object
in the graph can be reached (3), effectively enabling navigability.
Simple method calls not involving object references, can be handled
by the standard web service infrastructure without intervention.
This approach requires two distinct web service abstraction layers,
both on the client (in the form of custom proxies) and on the server
(in the form of a .NET Remoting extension). In the next section, we
present an elaboration of the general idea by using a more detailed
method call scenario.
Remote Method Calls
To make invocations transparent, we introduce two new (non-.NET Remoting)
proxies that will reside on the client and collaborate in order to
represent a remote (server-)object on the client. The transparent proxy1
mimics the interface of the remote object whereas the real proxy hides
communication details. Both of them have only their name in common
with the .NET Remoting proxies! In this subsection we refer only to
the real proxy. On the server side, a custom message sink is inserted
on top of the server channel sink to handle a client’s request.

Figure 6 An object reference URL.

Table 1 Mapping an object's interface. The
real proxy can be partially generated by extracting the interface of
the class it will represent. However, some modifications to this interface
are necessary when generating the proxy. These have to do with the
limitations of web services concerning the notion of object references.
As mentioned before, web services cannot transport objects (or better:
references to objects). Only types that have an equivalent SOAP type
[Box00] representation can be transported, which comes down to (C#)
simple and structured value types and strings. This means that each
time a non-transportable type is encountered in a method signature
(the return type or a parameter type), it will be mapped to the transportable
string type. An example of the different possibilities is given in
Table 1. We can see here that every time a class type is encountered,
it is replaced by a string type. At runtime, this string will act as
a container for the object reference, represented by a web service
URL. An example of such an URL is given in Figure 6. We need to include
the type of the object reference in the URL for an optimization concerning
the sending of collections/arrays. Without going into too much detail,
we send all the references in a collection in one message to limit
the number of requests. Since many collections can contain objects
of arbitrary types, we need to dynamically determine the right proxy
for each reference and we can do this by including the type in the
URL of every collection element.
We use three different methods to marshal different (object) types.
Objects that are normally marshaled by reference by the Remoting
infrastructure are also marshaled by reference by our extension using
the URL representation
as presented in Figure 6. Primitive types are marshaled by value
and can be transported directly using SOAP messages without extra intervention.
Complex value types (structs in C# [Alb01]) are also transported
directly,
except if they contain methods. In the latter case we use a third
technique that combines marshal-by-value and marshal-by-reference.
This hybrid
technique first makes a server-local copy of the object and then
creates a URL reference to that copy. The copy is required to enable
several
consecutive method-calls on the same struct-instance. Not doing so
would result in a new volatile copy to be made for each call, hence
losing the information from possible previous calls (meant for the
same instance) in the process.
An alternative approach to achieve correct transport of complex types
with methods is to always transport only the data in the instance
using marshal-by-value. This data can then be loaded into a corresponding
instance on the client that would act as a virtual proxy (does
not communicate with the server but does represent a server type) that
contains an implementation of the required methods. This solution
would
be more complicated to implement, while the first proposed method
can reuse the existing marshal-by-reference facility. Another disadvantage
of the alternative solution is the necessity to have the method
implementations
available on the client, causing possible hazards with versioning
and
incompatibilities with the .NET Compact Framework.
If a method does not contain non-transportable types, it can be
offered in the interface unmapped and can be invoked without special
intervention.
On the other hand, if a method contains mapped parameters or return
types, then the default mechanisms cannot be used and the invocation
needs special care both on the client (handled in its proxies)
and on the server (using a sink object) to take care of the marshaling.
A case where the return type is mapped will be discussed here.
Suppose we want to invoke the method MyClass GetMyClass() on
a remote object
that we can reach via a web service on a known URL. Through the
mapping mechanism this method will be exposed as String GetMyClass()
and
will be available as such in the real proxy on the client. The
sequence of steps that will take place when calling that method
is shown in
Figure 7 and is explained in the following paragraph. 
Figure 7 Remotely invoking a method. When
calling the method, all the details of that call are serialized
into a SOAP message and this message is sent to the known URL
(1). The method is actually called on a web service proxy that
uses the standard class library of the .NET Compact Framework
to hide the communication details from the caller. The proxy
classes for the real proxy can be generated with the standard
.NET tools (from our custom WSDL file, see further) The SOAP
message then arrives at the server and is accepted into the
.NET Remoting infrastructure. Here it is automatically deserialized
into an IMessage object containing the same information as
the SOAP message. After that, it is inserted into the sink
chains, which means that our own custom sink object will get
a chance to process the IMessage. In this case, the sink just
passes the IMessage further up the chain (it does not contain
any arguments) so the call is eventually invoked (2). If the
method had contained mapped parameters, its arguments would
have contained URLs that refer to other objects. These URLs
should than first have been replaced by the actual object references
before the IMessage is further propagated. The return value(s)
of the method call will also be intercepted by our message
sink (3). In response it will expose the returned object as
a web service and replace the object reference in the return
value with the URL of the created web service. Also, an extra
reference to this object must be stored on the server to prevent
it from being garbage collected. Whenever the returned object
is a (non-primitive) value type (struct in C#), a local copy
is stored to preserve the right semantics (see earlier in this
section). The modified IMessage is now handed over to the next
sink object to eventually be serialized to a SOAP message and
sent back to the client (4). When the SOAP message is received,
it is deserialized. The returned URL is then given to the proxy,
which will give it back to its caller — which will in
fact be a transparent proxy (see next section). The caller
can in turn start invoking methods on the returned ‘object’ represented
by the new web service. This will happen by instantiating a
new real proxy for the corresponding type, and initializing
it with the given URL.
The mechanism described above implies that proxies are available
a priori for each used type. We do not think this introduces
a serious limitation in this case because the programmer always
knows which types he will use at compile time (not taking into
account reflection-like mechanisms). Proxy generation at design
time will in fact boost performance by taking away the processing
cost of generating proxies at run time. While the mechanisms
described up till now do enable basic communications, directly
using real proxies does not provide for much transparency.
The caller does not see the real method signatures and has
to manipulate URLs instead of real object references. In the
next subsection, the transparent proxy is introduced in order
to solve this problem.
Providing a Transparent Client Interface
To make the approach described above more transparent to
the caller on the client, an extra level of indirection is
introduced
by adding a transparent proxy that interacts with the already
discussed real proxy. The interface of the transparent proxy
will mimic the interface of the object on the server that it
represents, effectively providing transparency. Table 2 shows
the interface of the transparent proxy and its relation to
the real proxy and the real object. The similarity between
the interfaces of the transparent proxy and the real object
are obvious. The only difference is that the underlying Car object is physically different, indicated in the interface
as the T namespace (including the namespace will not be necessary
in practice). In the transparent proxy, T.Car refers to the
other transparent proxy type for the real Car object. The mapping
between the different interfaces is done behind the scenes
by the web service abstraction layers. The application programmer
only gets to see the transparent proxy, while the server only
needs to take into account the real object’s interface.
Table 2 The transparent proxy interface and
its correspondence to the real proxy and real object. Whenever
a method, invoked on a transparent proxy, contains instances
of other transparent proxies in its arguments, the transparent
proxy will translate these arguments into their corresponding
URLs before forwarding the call to the real proxy. The reverse
translation is done with returned values. The real proxy in
turn hides the rest of the communication details as discussed
in the previous section. We illustrate the mechanism of transparent
proxies in the scenario depicted in Figure 8.

Figure 8 Transparent proxies hiding the URL
object references.
This scenario starts when the transparent
proxy objA* (the * indicates that it mimics the interface of
the remote object A) receives a response from the real proxy
after calling its GetObjectB() method. This is where the scenario
presented in Figure 7 ended by returning a URL to the caller
of objAProxy, which is represented by objA* in the current
scenario. The returned value is the URL to the web service
of object B. The rest of the scenario goes as follows. Upon
receiving the URL, the transparent proxy creates the necessary
proxy objects that will enable the client to transparently
work with the new object’s web service. It delegates
this task to the dedicated objectActivator – a proxy
factory – by sending it the create() message (1). This
objectActivator will check its cache to see if it
already contains a transparent proxy that refers to the given
URL. If none is
found, it will create a new one and add it to the cache (2).
By doing this we assure that only one reference to the remote
object exists from within each client. A corresponding real
proxy is also created (3). Eventually a reference to the newly
created transparent proxy objB* is returned to objA* (4), which
can in turn return it to its own caller (probably a local client
object). The programmer only gets to see the transparent proxies
objA* and objB*, the rest happens automatically behind the
scenes.
Up till now we discussed our basic scheme. We did not give
an answer to requirement 3 (callbacks from the server or events)
yet. We also need to think about a mechanism for distributed
garbage collection, preventing clients from influencing the
server objects in malicious ways. These two extensions of the
basic scheme are discussed in the next section.
4 EXTENSIONS FOR LIFETIME MANAGEMENT AND
EVENTS
The previous section explained how references to remote
objects
can be obtained and how method calls can be carried out in
a transparent fashion. However, there should also be a mechanism
to manage the lifetime of remote objects that are accessed
in this way. The server needs to know which objects are still
referenced in order to carry out meaningful garbage collection.
Requirement 3 also states that events on the server should
be capable of being propagated to the clients. The mechanisms
for addressing these two issues are presented in this section.
Distributed Lifetime Management
Distributed garbage collection is all about keeping track
of remote references to an object and letting them play a role
in the life cycle of the object. The goal is to prevent remote
objects either from living forever or from being deleted too
soon. Without further precautions being taken, the first case
would apply to the approach explained so far because we only
increase and do not decrease the reference count on the server.
Whenever a client gets a reference to an object on the server,
the object’s local life cycle (the one of its proxy)
will not be known to the server, which will result in an object
that lives eternally. Note that we do not address the inverse
problem of managing the life cycle of objects on the client
that are referenced by the server because until now this has
not been capable of happening. This client/server approach
rules out the problem of dealing with circular references,
which can only occur if an object acts as both client and server.
We are only providing a view of the server’s object graph
on the client, nothing more, nothing less.
We propose the simple method of just letting the garbage
collector on the client do its work on the proxies and, whenever
a transparent
proxy is destructed, notifying the server of this event.
This technique comes down to a synchronization of life cycles
rather
than a fully fledged distributed garbage collection mechanism.
Although easy to implement and working well in our specific
case, it requires the objectActivator (proxy factory) to
implement all references to transparent proxies as weak
references2 because
otherwise the proxies would never qualify for garbage collection.
A survey of more elaborate techniques for distributed garbage
collection is given in [Pla95]. [Vei03] presents a distributed
garbage collector that improves the current mechanisms used
in .NET. The garbage collector is implemented in Rotor [Mic2]
using the sink based extension mechanism.

Figure 9 Lifetime synchronization. Our
basic approach is illustrated in Figure9. As explained in the
previous section, the server adds an extra reference to an
object each time it is requested by a client. We only increment
the reference count by a maximum of one for each client. Once
a transparent proxy on the client is not referenced anymore,
it is destroyed by the local garbage collector (1). This results
in the invocation of the destructor of that proxy. The transparent
proxy reacts to this event by invoking the EndLife() method
on a special garbage collector proxy (WSGCProxy), giving its
URL as argument (2). The message is received at the server
(using the mechanisms described earlier), where a special garbage
collecting object (WSGC) will remove a reference to the corresponding
remote object (3). Hereafter the garbage collector of the server
can proceed with its tasks. Because the reference count of
the object on the server is lowered, the object could possibly
be removed in the next run of the garbage collector.
Of course this method does not take into account the unexpected
connectivity loss of a client. The unexpected loss of a client
will result in eternal life for its referenced objects because
it cannot notify the server of object destruction. Since
wireless networks are common, portable devices suffer connectivity
losses
regularly and a complementary solution has to be added. A
simple and satisfactory solution is to implement a simple leasing
system where the client announces its presence to the server
at regular intervals. When the server does not get any life
signs for a specified amount of time or after an active poll,
it can delete all the references associated with that client.
Because life signs can get lost, this solution can fail but
this technique detects whether an object can be destroyed
with
a high probability.
Remote Events
Using the given descriptions, invocation from client to server
becomes possible. What is lacking here is a mechanism
for notifying clients of events generated by a remote object.
This will require
the client to act as a (web)server; we assume that firewalls
and other filtering mechanisms (e.g. Network Address
Translation)
are configured to allow all inbound traffic. An easier
solution would be for the client to use a polling mechanism
but this
will not be further considered here since it is not a
real eventing system.
In C# (probably the most popular .NET language) the keywords
event and delegate are provided. A (multicast) delegate
is a special object that can contain pointers to methods
in
other objects, provided that these methods have the
same signature
as the delegate declaration. These methods can consequently
be called all together by triggering the delegate.
The event keyword is actually an access modifier on a delegate
to prevent
external triggering of the delegate. Other objects
can
subscribe to an event by instantiating the delegate
with one of their
methods and adding it using the += operator. How these
events and delegates are integrated into the previous
parts is discussed
below (see Figure 10).
Figure 10 Remote events. In
the same way that the transparent proxy mimics the interface
of a remote object, it also mimics the events published by
that object. To subscribe to an event published by the transparent
proxy objA*, one calls the subscribe() method with an instance
of the appropriate delegate as its argument (1). The standard
mechanism to subscribe to an event cannot be used because the
+= operator cannot be overridden (we need this in order to
invoke subscribe() (2)). As a consequence, this part cannot
be made completely transparent. Next, the transparent proxy
objA* passes the request to the client’s eventHandler object (2). The eventHandler acts as a transparent proxy in
the sense that it does the necessary translations of object
references to URLs, but it does more than that (see further).
The request is then passed to the real proxy (3) belonging
to the eventHandler object, which sends the message to the
server. A delegate is identified by an ID number in this stage,
so the server can find the right delegate. When the message
arrives at the server, the custom sink object (not shown in
the figure) routes the request to the eventListener object,
which subscribes itself to the event in place of the transparent
proxy objA* (4). When the event occurs (5), the eventListener is notified. The eventListener then calls its proxy (a custom
server proxy) to translate the event arguments and send them
to the eventHandler on the client. This is accomplished by
running a simple web server [Pra03] on the client and publishing
the eventHandler’s interface on a well-known URL. The
eventHandler can, if necessary, call the corresponding delegate
on the client to raise the event locally (6). Thus it will
seem that the event has occurred locally. Again, every action
originally takes place at the server. The client just gets
a view of the activities as they are happening on the server.
If the eventing system as explained above is used and the
required server-to-client communication mechanism is in place,
we could
reuse this facility to make the garbage collection mechanism
more efficient. Instead of notifying the server each time a
client proxy is destroyed (as explained in the previous section),
the server could ask the client which objects may be destroyed – just-in-time – whenever
its own garbage collector runs. This would reduce the amount
of garbage-related messages because they can then be grouped
into larger aggregated messages. Mind that the trivial approach
explained here could potentially slow down the server garbage
collector due to the delay caused by the requested network
message. Furthermore, new infrastructure parts will be needed
on the client and server to make this work. We do not discuss
this approach further in this article.
5 IMPLEMENTATION OF THE MODULES TO SUPPORT THE PROPOSED
CONCEPTS
An implementation of the basic ideas was carried out to prove
the feasibility of the proposed concepts. The results of
the implementation can roughly be divided into two parts:
a C#
code generator for the client side proxies and an extension
for the .NET Remoting infrastructure in the form of a channel
sink and supporting objects.
The code generator was implemented in two steps. First
a WSDL generator was developed. It takes one or more
existing classes
(residing in compiled assemblies) as input and generates
WSDL files for the choosen types as output. The outputted
WSDL represents
the real proxy interface, having reference types mapped
to
strings. Next, this WSDL is automatically transformed
into real proxies using standard provided classes (or tools)
in the .NET Framework class library. In a second phase
a code
generator for the transparent proxies was implemented.
This was accomplished using the excellent support for
dynamic
code generation and compilation of the .NET class library.
All the functionality mentioned was then integrated into
one tool which enables one-click generation of all
the needed proxies.
The functionality needed by all proxies (such as the
objectActivator) was split off into a separate common
library module that
has to be included with each client. Our generator
tool can be
set to output a compiled assembly of proxies, ready
to be used. By importing this assembly into a project (in
Visual
Studio.NET,
see Figure 11), the programmer gets a view of all the
classes as he would expect them on the server, thus
fulfilling requirement 4.

Figure 11 Using the generated proxies. For
now our generator generates transparent proxies only for .NET.
Real Proxies can already be generated for other platforms such
as Java because they are solely based upon the WSDL file. We
have split the code generation into a few steps to facilitate
the adaptation of code generation for other (non-.NET) programming
languages. Especially the generation of the intermediate WSDL
files opens up the possibility of using existing tools to generate
real proxies in other languages without having to recode the
entire logic. To be even more reusable, we should integrate
all neccesary information – extra information to generate
transparent proxies – into the WSDL file in the future.
This can be accomplished by using a distinct XML namespace.
Development of the channel sink took longer then expected
due to the many little pitfalls of the Remoting framework.
The
channel sink component is responsible for mapping the run-time
arguments and return values back and forth to URLs. The reverse
mapping is necessary for the WSDL generator, so the mapping
part is split off in a separate component. In summary, the
channel sink undertakes four steps in intercepting messages:
- Check the input message and only accept objects implementing
IMethodMessage. We do not handle constructor messages
for example.
- Adapt the incoming message:
- Search for references in the parameter list.
- Skip simple messages (containing only primitive
types).
- Convert the references into real object references
by searching the server’s hash table. Create a
new writable Imessage object, copy the data from the
original
message and
replace
the references.
- Forward the newly created message to the next sink
in the chain.
- Adapt the return message:
- If the return type is primitive, the instance is
marshaled by value and directly sent back.
- If the return type has to be marshaled by reference,
a unique ID is generated to be able to construct a valid
URL.
Next,
the instance is published as a web service on this
URL and the mapping between URL and real object reference
is
saved
in a hash map, which also places an ex-tra reference
to the object on the server for use in the distributed
garbage
collection.
Finally the return message is changed with the marshaled
return value.
- In case of a complex value type with methods, a
local copy of the instance is first created and then,
the mechanism
of
b is followed.
Inserting a channel sink in the server formatter sink chain
can be accomplished by adding a few lines of code to the server
application or even simply by adding some configuration information
to the application’s standard configuration file. The
latter one requires no source code changes to the server. The
code below shows the few lines of code that need to be added
to the server, assuming that a SoapFormatterSink is already
present. This shows the low impact on the server, supporting
requirement 5.

At the client side the proxies need to be imported
(see Figure 11) and some bootstrap code (shown below) needs
to be manually inserted by the programmer. This can be done
using just a few lines of code. From here on everything is
handled behind the scenes through transparent proxies only.
 Our
implementation was tested against an existing application of
a company active in the warehouse automation sector. This automation
is accomplished using automated guided vehicles (AGVs). To
enable rapid application deployment they developed an inte-grated
designer suite offering the basic building blocks of a warehouse
application. The suite is fully written using the .NET Framework.
It includes generic building blocks for logging, scheduling
transports and user interfacing. The user interfacing building
blocks communicate with the other parts using .NET Remoting
in a client/server fashion.
Our test case was a smart client application that acted as
a simplified graphical user interface (GUI) to the warehouse
application. The advantage of our approach in this specific
case was the possibility to reuse the existing GUI code with
only minor adjustments because the generated transparent proxies
use the same class names as the full applications. Two objects
were relevant in this application, namely Project and Agv.
The operations that were used to do some testing are summarized
in Table 3. The generated proxies for the two objects were
compiled into an assembly of 20 KiB3 . The client’s
common library requires 16 KiB. The measured durations for
operation
executions are presented in
Table 4 below. The table contains measurements using our solution
and using the Remoting-Remoting case (using the HttpChannel).

Table 3 Test operations.

Table 4 Performance measurements. From
these limited measurements we can see that performance of our
approach is slower than the Remoting-Remoting case. This is
probably also due to our less-than-optimal implementation of
the concepts. With some optimization we believe that our implementation
can deliver better results that are acceptable for small applications.
The large delay of the GetName() operation (first row in Table
4), in the Remoting-Remoting case is caused by the dynamic
generation of proxies. This type of delay always occurs when
invoking the first method on a remote object and has nothing
to do with the type of its return value/parameters. This supports
our early decision not to port the complete .NET Remoting infrastructure
to the .NET Compact Framework. Further tests showed no performance
decline when offering many objects (tested with arrays of 3,
30, 300 and 3000 objects).
6 RELATED WORK
The consuming of web services on mobile devices has been
emerging due to the growing availability of Wifi-, or Bluetooth-enabled
PDAs and smart phones. These web services have been mainly
limited to simple request/response services, such as obtaining
weather or news information. To enable remote events, as discussed
earlier, a mobile web server will be needed. A proposal to
implement such a server, keeping in mind the resource constraints,
is given in [Pra03]. To lower the device’s requirements,
some constraints were introduced. One of them is to allow only
simple SOAP types. This would not be a problem in integrating
it with our solution, because we do not use complex SOAP types.
In [Cam00], techniques for optimizing the performance of
Java RMI are proposed. The optimizations are made with wireless
communication and resource-constrained devices in mind, making
Java RMI more suitable for mobile devices.
An approach to optimizing the use of web services on resource-constrained
devices by applying specialized code generation techniques
is presented in [Eng]. Also, some runtime optimizations
are implemented using the gSOAP environment, which is portable
to most platforms including Pocket PC (which can run the
.NET Compact Framework).
Middsol [Mid] provides standard CORBA inter-process communication
for the .NET Compact Framework. This support is provided
in the form of an assembly (520 KiB) that needs to be
included on the mobile client. While being very useful, this
solu-tion
does not allow one to directly connect to .NET Remoting
objects.
An approach that enables communication between the .NET
(Compact) Framework and long-lived embedded devices
is proposed in
[She04]. It isolates applications from the underlying
wire protocol
by using application-level bridges. This is similar
to what we are accomplishing by using independent proxies
on the
client.
The approach in [Vei04] enables the .NET Compact Framework
to communicate with a .NET Remoting infrastructure
using bridges based on web services. The main focus
of the
paper is on object
replication on mobile devices to enable connectionless
operation and boost performance. As in our approach,
automatic proxy
generators are provided.
7 CONCLUSION
To enable the introduction of smart clients (PDAs,
smart phones) into existing distributed applications,
we proposed
an approach
that dynamically maps web services to .NET Remoting.
This approach enables the quick development of
applications that interact
with remote objects, solely using the .NET Compact
Framework. By presenting a transparent interface
using proxies,
the
programmer does not have to worry about any communication
details. The
solution is fully generic so it can be used for
any existing ap-plication without specific modifications.
Using our code generation tool, proxies are generated
fully automatically simply by selecting the
required classes
in an assembly. Thus a complete representation
of the needed server-objects
becomes available at the client in the form
of proxies that
mimic these objects. This also enables the
reuse of possibly existing (.NET Full Framework) client
code.
The impact
on the server is minimized by the implementation
of all necessary
logic using just one sink object (a Remoting
extension). This
sink can be inserted into the .NET Remoting
infrastructure by adding as little as three lines of code or
even simply by modifying the application configuration
file, without
influencing
the rest of the application. In addition, the
portability
to other client platforms is easy. It would
only
require an extension
of the C# code generator for the transparent
proxies. The server side requires no modifications.
To refine the solution, two paths can be further
pursued. First, the implemented modules can
be completed by
including an implementation
of the proposed garbage collection and eventing
concepts. Secondly, we can search for good
solutions to handle
the more efficient
communication of frequently used classes
such as collections and, more in general, all classes
common
to the class
libraries of both client and server.
Footnote: 1 The
names for these proxies were inspired by the names of the
proxies in .NET Remoting. To avoid any confusion, we do not
refer to the .NET Remoting variants further in this text
unless explicitly stated.
2 A weak reference is an object
reference that does not influence garbage collection. Objects that
only have weak references may be destroyed by the garbage collector.
A user has to acquire a strong reference to the target object before
being able to use it.
3 KiB is short for kibibyte,
where kibi=210 (an IEC prefix). KB is short for kilobyte, where kilo=103
(an SI prefix).
REFERENCES
[Alb01] B. Albahari, P. Drayton, and B. Merrill, C# Essentials.
O’Reilly, 2001.
[Alm01] J. P. Almeida, L. Ferreira, and M. J. van Sinderen, “Web
services and seamless interoperability”, 2001 [Online], Available:
http://wwwhome.cs.utwente.nl/~pires/ publications/eoows2003.pdf
[Boo03] D. Booth, H. Haas, F. McCabe, E. Newcomer, M. Champion,
C. Ferris, and D. Orchard, “Web services architecture,” 2003.
[Online]. Available: http://www.w3c.org/TR/2003/WD-ws-arch-20030808/
[Box00] D. Box, D. Ehnebuske, G. Kakivaya, A. Layman, N. Mendelsohn,
H. F. Nielsen, S. Thatte, and D. Winer, “Simple object access
protocol (soap) 1.1,” 2000. [Online]. Available: http://www.w3.org/TR/2000/NOTESOAP
20000508/
[Cam00] S. Campadello, O. Koskimies, K. Raatikainen, and H. Helin, “Wireless
java rmi.”
[Eng] R. van Engelen, “Code generation techniques for developing
light-weight xml web services for embedded devices.”, [Online],
Available: http://websrv.cs.fsu.edu/~engelen/SACpaper.pdf
[Mcl03] S. McLean, J. Naftel, and K. Williams, Microsoft .NET REMOTING.
Microsoft Press, 2003.
[Mic] “Microsoft .NET framework development center.” [Online].
Available: http://msdn.microsoft.com/netframework/
[Mic2] “Microsoft Rotor - Shared Source Common Language Infrastructure”,
[Online], Available: http://msdn.microsoft.com/net/sscli
[Mid] MiddSol, “Middleware solution for integrating .net, j2ee
and corba.”, [Online], Available: http://www.middsol.com/MinCor/index.html
[Pla95] D. Plainfossé and M. Shapiro, “A survey of distributed
garbage collection techniques.”, 1995, [Online], Available:
http://mega.ist.utl.pt/~ic-arge/arge-96-97/artigos/
[Pra03] D. Pratistha, N. Nicoloudis and Simon Cuce, “A micro-services
framework on mobile devices,” 2003. [Online]. Available: http://plato.csse.monash.edu.au/MobileWebServer/pervasive3.pdf
[She04] R. Shenoy and K. Moore, “Sustaining the integration
of long-lived systems with .NET”, 2004, [Online]. Available:
http://www.hpl.hp.com/techreports/2004/HPL-2004-133.pdf
[Sun] “Java RMI” [Online]. Available: http://java.sun.com/products/jdk/rmi/
[Vei03] L. Veiga and P.Ferreira, “Complete distributed garbage
collection: an experience with Rotor”, [Online], Available:
http://csce.unl.edu/~witty/sp2004/csce496/repository/upload/10.pdf
[Vei04] L. Veiga, N. Santos, R. Lebre and P.Ferreira, “Loosly-Coupled,
Mobile Replication of Objects with Transactions”, 2004, [Online],
Available: http://www.gsd.inesc-id.pt/~pjpf/icapds-2004.pdf
[W3c02] “W3c web services activity.” [Online]. Available:
http://www.w3c.org/2002/ws
[W3c03] R. Chinnici, M. Gudgin, J.-J. Moreau, and S. Weerawarana, “Web
services description language (wsdl) version 1.2,” 2003. [Online].
Available: http://www.w3.org/TR/2003/WD-wsdl12-20030303/
[Wig03] A. Wigley and S. Wheelwright, Microsoft .NET Compact Framework
(Core Reference). Microsoft Press, 2003
About the authors

|
|
Bert Vanhooff received his master’s
degree in Computer Science in 2004 from the K.U. Leuven and is
now a PhD student at the K.U. Leuven. His main research interests
are situated in the area of Model Driven Development and the application
of that paradigm to Component Based Software Engineering and model
transformations. He can be reached at bert.vanhooff@cs.kuleuven.be. |

|
|
Davy Preuveneers received his MS
degree in Computer Science in 2002, and his MS in Artificial
Intelligence in 2003 from the K.U. Leuven. Since 2003, he is
working towards his PhD at the Department of Computer Science
of the K.U. Leuven. His research is focussed on context-aware
service interaction and adaptation, in particular in mobile and
pervasive computing environments. Contact him at davy@cs.kuleuven.be.
|

|
|
Prof. Dr. Ir. Yolande Berbers received
her PhD degree from the K.U. Leuven in 1987. She is currently
a full professor at the Department of Computer Science at the
K.U. Leuven and a member of the DistriNet research group. Her
research interests include software engineering for embedded
and real-time systems, model-driven architecture, context-aware
computing, distributed and parallel systems and distributed computing,
and multi-agent systems with emergent behaviour. She runs several
projects in cooperation with other universities and/or industry.
She can be reached at yolande@cs.kuleuven.be.
|
Cite this article as follows: B. Vanhooff, D. Preuveneers, Y. Berbers: “.NET
Remoting and Web Services: A Lightweight Bridge between the .NET Compact
and Full Framework”, in Journal of Object Technology, vol. 5,
no. 3, April 2006, Special issue: .NET Technologies 2005 Conference,
pp. 59-81 http://www.jot.fm/issues/issue_2006_04/article3
|