This is a long post so I’ll summarize my findings up front.
Summary:
Read on for the details…
Details:
So you’ve read all the guidance about how and when to use .NET Remoting and now want to see a working code sample of this in action?
Building the .NET Remoting solution
I have broken this solution into three projects:
NOTE: I repeat code blocks throughout this post and will highlight changes made in red.
Let’s start with an interface:
namespace SharedContract
{
public interface IAmTheSharedContract
string Echo(string input);
}
Using a shared interface is inline with the .NET Remoting guidance. An interface based approach reduces the code shared between client and service and, as you will see, allows for re-use for other distributed applications stacks such as Windows Communication Foundation (WCF) and ASMX. This is interface above is what every client will program against.
Next we need to implement it:
namespace Service
class ServiceImplementation : MarshalByRefObject, IAmTheSharedContract
public string Echo(string input)
Console.WriteLine("Received input: " + input);
return input;
Next we need to host the service implementation. Every distributed application stack has different hosting options and techniques. Isolating this code from the implementation is critical to ensure easy migration and portability.
Here is the code needed to host it for .NET Remoting:
class Program
static void Main(string[] args)
RemotingConfiguration.Configure("Service.exe.config", true);
Console.WriteLine("\nThe service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.\n");
Console.ReadLine();
The configuration for hosting this .NET Remoting service is as follows:
<!-- Remoting hosting section -->
<system.runtime.remoting>
<application>
<service>
<wellknown mode="SingleCall" type="Service.ServiceImplementation, Service" objectUri="server.rem" />
</service>
<channels>
<channel ref="tcp" secure="true" port="8080" />
</channels>
</application>
</system.runtime.remoting>
You will notice that I am using the new secure TcpChannel provided in .NET Remoting 2.0. This new secure channel provides identification, encryption and signing simply by adding the secure=”true” attribute.
You now have a complete .NET Remoting service.
And now we need a client:
namespace Client
IAmTheSharedContract proxy = ClientProxyFactory.CreateProxyInstance();
Console.WriteLine("Calling the " + ClientProxyFactory.Platform + " endpoint:");
Console.WriteLine("\tResult: " + proxy.Echo("Testing " + ClientProxyFactory.Platform + " endpoint"));
You will notice that the client does create the proxy directly. As per our guidance we are using a client proxy class to astract the .NET Remotingisms from the client code. The proxy class looks like this:
class ClientProxyFactory
static ClientProxyFactory()
RemotingConfiguration.Configure("Client.exe.config", true);
defaultPlatform = (ClientProxyFactory.CommunicationPlatform)Enum.Parse(
typeof(ClientProxyFactory.CommunicationPlatform),
ConfigurationManager.AppSettings["communicationPlatform"]);
static CommunicationPlatform defaultPlatform;
static ChannelFactory<IAmTheSharedContract> factory = null;
public enum CommunicationPlatform
Remoting
public static CommunicationPlatform Platform
get
return defaultPlatform;
public static IAmTheSharedContract CreateProxyInstance()
return CreateProxyInstance(defaultPlatform);
public static IAmTheSharedContract CreateProxyInstance(CommunicationPlatform platform)
IAmTheSharedContract proxy = null;
switch (platform)
case CommunicationPlatform.Remoting:
proxy = (IAmTheSharedContract)Activator.GetObject(typeof(IAmTheSharedContract), "tcp://localhost:8080/server.rem") as IAmTheSharedContract;
break;
return proxy;
The ClientProxyFactory is used to create a proxy dependant on the distributed application platform. The critical parts of this class are the constructor, where the chosen platform is set, and the CreateProxyInstace(), where the service proxy is create. The distributed application platform to use is picked up from config and maps to the CommunicationPlatform enumeration. The various connection URIs could be in config as well.
The configuration for this client looks like this:
<!-- client proxy config section -->
<appSettings>
<!-- use appSetting to configure base address provided by host -->
<add key="communicationPlatform" value="Remoting" />
</appSettings>
<!-- Remoting configuration -->
<channel ref="tcp" secure="true" tokenImpersonationLevel="identification" />
You will notice that I configure a channel for the client-side as well. This is required for the secure TcpChannel to ensure that the client channel is enabled for security as well.
And now you have a complete .NET Remoting application using the our .NET Remoting programming guidance.
The next step is to enable the solution for WCF.
Enabling the solution for WCF
Now we’ll convert this application to use Windows Communication Foundation (WCF) (Indigo).
First we need to modify the contract:
[ServiceContract]
[OperationContract]
All we need to do is decorate the interface with the ServiceContract attribute and the methods to expose with the OperationContract attribute. This will be automatically picked up by WCF to enable exposing this interface as a WCF endpoint.
What do we need to do to the implementation class? NOTHING.
To support a WCF endpoint we need to add some hosting code:
// Get base address from app settings in configuration
Uri baseAddress = new Uri(ConfigurationManager.AppSettings["baseAddress"]);
ServiceHost serviceHost = new ServiceHost(typeof(Service.ServiceImplementation), baseAddress);
// Open the ServiceHostBase to create listeners and start listening for messages.
serviceHost.Open();
Console.WriteLine("\nThe services are ready.");
This hosting code gets the service address from config and then uses ServiceHost to configure the WCF endpoints. The app.config file contains the configuration for WCF hosting.
We need to add some code to configuration to enable the WCF endpoint:
<!-- WCF hosting section -->
<add key="baseAddress" value="net.tcp://localhost:8088/wcfservice" />
<system.serviceModel>
<services>
<service
type="Service.ServiceImplementation, Service">
<!-- use base address provided by host -->
<endpoint address=""
binding="netTcpBinding"
bindingConfiguration="Binding1"
contract="SharedContract.IAmTheSharedContract,SharedContract" />
</services>
<bindings>
<netTcpBinding>
<binding name="Binding1" />
</netTcpBinding>
</bindings>
</system.serviceModel>
This configuration establishes a TCP endpoint using the WCF NetTcpBinding.
Now the service is hosting both .NET Remoting and WCF!
On to the client…
The code in the client Main() from before does NOT change!
The programming against the shared interface remains the same but we need to update the ClientProxyFactory to enable it to connect to WCF endpoints:
Remoting,
WCF
case CommunicationPlatform.WCF:
if(factory == null)
factory = new ChannelFactory<IAmTheSharedContract>("");
proxy = factory.CreateChannel();
As you can see we simply added WCF to the CommunicationPlatform enumeration and then added code to create a proxy to the WCF endpoint using the ChannelFactory<T>.CreateChannel() API.
This requires additional client configuration for the WCF endpoint:
<add key="communicationPlatform" value="WCF" />
<!-- WCF hosting configuration -->
<client>
<endpoint name=""
address="net.tcp://localhost:8088/wcfservice"
contract="SharedContract.IAmTheSharedContract, SharedContract">
</endpoint>
</client>
We changed the CommunicationPlatform value to now use WCF and then added the configuration to point to the WCF endpoint.
Now you have a client that talks both to WCF and .NET Remoting!
To change which endpoint you are talking to requires only that you change the CommunicationPlatform valule in the Client.exe.config file.
Enabling the solution for ASMX
Now you may be wondering if this conversion is possible to ASMX Web Services. Yes, it is!
Here are the steps to convert to support ASMX as well.
First update the shared interface:
[WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1,EmitConformanceClaims=true)]
[WebMethod]
As you can see, ASMX is enabled simply by further interface and method decoration to enable ASMX as well. The WebServiceBinding attribute is new in .NET Framework 2.0 and allows ASMX to support declaration of your web service methods through an interface.
What changes in the service implementation? NOTHING! That is pretty cool.
ASMX in .NET Framework 2.0 will automatically pick up the fact that the service implementation implements and interface marked with the WebServiceBinding attribute and will generate a WSDL based on the interface methods marked with WebMethod.
If you want to change the namespace of the service then you can decorate the implementation class with a WebService attribute and control the namespace as well. This will NOT interfere with hosting this class in .NET Remoting or WCF.
Next we look at the hosting problem. When I built this sample I took the simple route:
<%@ WebService language="C#" class="Service.ServiceImplementation,Service" %>
Because of the changes in .NET Framework 2.0 the ASMX file will be compiled on the fly so no building is required. If you go to http://localhost/<VDir>/WebService.asmx you will see that the ASMX web service is now hosted. Go ?wsdl to make sure that the WSDL is also generated.
You are now hosting this same interface and implementation in ASMX as well.
Next we move on the client. On the client-side we need to generate and ASMX client proxy. Use wsdl.exe /out:asmxProxy.cs http://localhost/<VDir>/WebService.asmx?wsdl to generate the client proxy class.
The generated proxy needs to be changed in the following ways:
And the ClientProxyFactory needs to be changed as well:
WCF,
ASMX
case CommunicationPlatform.ASMX:
proxy = new AsmxClientProxy() as IAmTheSharedContract;
As you can see we simply added ASMX to the CommunicationPlatform enumeration and then added code to create an instance of the generated ASMX proxy and return this proxy as the shared interface.
Now you can change the Client.exe.config to use the ASMX endpoint as well:
<add key="communicationPlatform" value="ASMX" />
And now you have one client that can talk to .NET Remoting, WCF and ASMX! All of these use the same shared interface!
Key Takeaways: