January 2004 - Posts

Web Services vs. Remoting

My last post on Remoting and proxy authentication elicited the following response from Simon Stewart.

 

>>Without knowing the exact details, wouldn't a web service have avoided these problems?

 

This brings up a very interesting question. When should I use .NET Remoting verses Web Services? This in fact gets even more interesting when we throw Enterprise Services into the mix, and this is an option that I always consider, but will not be addressing here.

 

There are numerous resources on the Internet that address this question, yet it still seems to be a difficult question to answer. I do not have the answer, only some ideas on a starting point.

 

To decide on which technology to use, some of the factors to consider include

 

  • Performance
  • Security
  • Interoperability
  • Visibility
  • Scalability

 

These factors assume that we are looking at a service-oriented architecture. One of the other factors, that I will not be addressing here, is the programming model. .NET Remoting provides a very flexible selection of programming models. And these would also weigh in on the decision.

 

Performance

This can be a very strong deciding factor in choosing not only between .NET Remoting and Web Services, but also the various combinations of hosts, channels and formatters used for .NET Remoting.

 

Security

While neither Web Services nor .NET Remoting provide a native security model, both are extensible enough to allow for a security model to be imposed on them. Both can also be hosted in IIS and utilize IISs support for SSL to provide security, without any extra coding on the part of the developer, though from a performance point of view this would not be the best option.

 

Interoperability

Interoperability defines what types of clients will be accessing the service. I might require any client on any platform to have access to the interface I am providing.

 

Visibility

I define the visibility as the number and types of client over what medium will access the service. Visibility introduces the possibility of firewalls and access to the system over the Internet.

 

Scalability

Scalability is the ability for the system to scale both upwards and outwards to handle higher request. The scalability requirements do not only help select between .NET Remoting and Web Services, but again also the kind of host I would select for a .NET Remoting solution.

Having said that, when looking at scalability I think we are reaching a point where many developers are forgetting that we still have bandwidth considerations and that server side scalability is not always the solution.

 

These factors are not viewed in isolation, but as a whole in context of the system performance and functional requirements.

 

Here is a quick example of how I might apply these factors to make a decision.

 

When performance out weighs things like interoperability, I believe .NET Remoting with a TCP channel and binary formatter, hosted in a Windows Service is the best .NET option. If scalability weighs into this, then .NET Remoting with Http channel and binary formatter hosted in IIS is a more suitable option, this would also be the case if there is a requirement to access the service over the internet and interoperability is not a factor.

 

If performance is critical as well as interoperability, then Web Services are clearly a better option. I have also used .NET Remoting to provide access to .NET clients and have a Web Service provide the interoperable interface to non-. NET clients.

Remoting and Proxy Authentication

Recently a friend was developing a system that required RPC.  A remoting server hosted in IIS seemed the ideal solution, except for one problem, the environment where the solution was intented to be implemented required that all traffic be routed through an authenticating proxy. After a quick search on Google it became clear that this functionality is not supported by .NET Remoting. Since Remoting works perfectly well through a proxy as long as the proxy does not require authentication I decided to investigate further. Taking a look at the code, the HttpClientChannel contains a private member called _proxyObject of type IWebProxy, this member is initially set to the default proxy setting provided by internet explorer, and if you have provided alternate proxy information through the channel properties collection UpdateProxy() method constructs a new WebProxy using this information, however this is limited to providing proxy address and port, not other proxy information.

Interesting limitations are apparent here, firstly there is no public way to provide a IWebProxy object and because of this you can not provide proxy authentication credentials, nor can you provide a bypass list. The bypass list from internet explorer is used unless you provide alternate proxy name/port information, in which case the internally constructed WebProxy is initialized to be bypassed for local traffic and the current machine IP, disregarding the information from Internet Explorer. While this makes perfect sense, I can not see what reason MS would have had not to at least provide some public means to provide a proxy object to be used for the channel. As I did not see an alternate solution to the problem, I decided that I would bite the bullet and use reflection to set the _proxyObject to a user created IWebProxy implementing object, the following code is an example of what I did

public static void SetChannelProxy( HttpChannel channel, IWebProxy proxy )
{
  FieldInfo clientChannelFieldInfo =
   
typeof(HttpChannel).GetField("_clientChannel",  
   
BindingFlags.Instance | BindingFlags.NonPublic);

  HttpClientChannel clientChannel = (HttpClientChannel)
  clientChannelFieldInfo.GetValue(channel);

  FieldInfo proxyObjectFieldInfo =
   
typeof(HttpClientChannel).GetField("_proxyObject",
    BindingFlags.Instance | BindingFlags.NonPublic);

  proxyObjectFieldInfo.SetValue( clientChannel, proxy );
}

The important thing to keep in mind with the above function is that you call it as the final step of the channel configuration otherwise your proxy object could be overwritten if you somewhere alter the 'proxyname' or 'proxyport' keys of the channel properties. To test the routine, I configured Squid on Linux and routed calls to a remoting object, when Squid was configured to authenticate the proxy clients I created an instance of WebProxy and configured the credentials and used the routine above to set the proxy for the channel, and to both my friend and my own relief it worked. This was also later tested and implemented in the live system.

As you may know from some of my other post/articles I would not typically recommend using reflection to manipulate non-public attributes, and I will not bore you with all the reasons at this point, but in this case I could not find any other solution that could be implemented within the constraints of the project. I hope someone could explain why this support was not provided, was it just a simple oversight or is there some deep dark architectural reason?

An alternative that I did consider was to write a new HttpChannel that provided support to configure the proxy, but just looking at the shear scope of the SSCLI code for the HttpChannel, I fealt that the QA, time and potential risks to implement a solution of this nature for the project at hand would not be feasable. I do however hope to get some time to undertake such an endeavour, maybe someone has already started such a project?

Cool Language Feature : Generic Constraints

Having played with generics since they where available in the SSCLI via the Gyro extensions, I have to say that this is my favorite new language extension. More specifically I really like the addition of constraints, I believe that the addition of constraints will reduce the requirement of policy and traits classes significantly. Now all I need to do is to get MS to share a version of Whidbey with me so I can experience the rest of the extensions!

Asynchronous Events

I just did an interesting exercise of considering a number of alternatives to firing events asynchronously. Here are the three alternatives I thought are interesting. At the end of this post I provide for some other possibilities, each with their own pros and cons.

 

For each version the following are assumed

 

public delegate void DataArrivedDelegate( object sender,

  DataArrivedEventArgs e );

 

public event DataArrivedDelegate DataArrived;