Sunday, September 11, 2011

Remoting Servers 101

Before I jump into this, I just want to explain that Remoting is an old .Net v1.1 technology and it is no longer supported. However it still gets the job done if that is what you are using already or if you need a really old code to talk to a really new code and you are not at liberty to use WCF. The following example I am going to provide shows .Net v2.0 talking to .Net v4.0. If you have the opportunity to design something from scratch with the time to learn how to do it correctly; please use WCF instead of Remoting. There is no point in using old coding if you can use the new stuff.

Introduction to Remoting
In this example you need to understand that there are two parts to Remoting always, there is the Client or Consumer and the Proxy or Remoting Server. Remoting is great for exposing parts of a dll to an older .Net version or to avoid dll hell in a sense. You can have a centralized location for your main or base dll and just have other components point to it. The benefit here is to not have to make sure that all locations have an exact copy of the latest dll (hence the mention of dll hell).

Remoting Anatomy
There are some basic parts that are involved in remoting and keep in mind a lot of these same concepts are now used in WCF. Remoting requires the following to work:

  1. You must use Remoting locally, it will not work across the net and it isn't safe to attempt it either. Not to mention that it would kill performance.
  2. You must have an Interface Library and that library must be identical for the client and the proxy.
  3. You must have a Remoting Project (you could probably get away without having it, but for simplicity's sake just have one).
  4. You must be able to host these projects in IIS. I have done this with IIS 5, 6 and 7. Trying to use casini in this case is just a pain in the ass, just use IIS.
Here is a picture of the projects I am used to using and seeing when I work with remoting:
Project Descriptions:
  1. BaseWebApp - ASP.NET v4.0 - This is the application or dll we want to expose. Please be aware that Session and other web related objects are not completely available during remoting access. This application is oblivious to the fact that the Remoting Server exists (kind of). Think of the Remoting Server as a parasite and the BaseWebApp as the host. You are going to need to put the RemotingServer and RSInterfaceLibrary into the BaseWebApp's bin folder, this will be explained more later.
  2. PublicWebService - ASP.NET v2.0 - This is the client project that will be consuming the remoting server or utilizing it in order to use the exposed dll. Notice that it is in an older .Net version and would not be able to use the target dll as a reference even if we wanted to. Unless you down graded, which is not suggested or good design.
  3. RemotingServer - ASP.NET v4.0 - This remoting server project will do all of the accessing of the target dll that we are exposing, hence being called the proxy. It is a proxy between the consumer and the exposed dll. This is necessary because we don't want to just allow the web service to have access to everything, only what is allowed by the remoting server.
  4. RSInterfaceLibrary - ASP.NET v2.0 - This remoting server interface library is .Net v2.0 because it can be used by the RemotingServer and the PublicWebService. I did this for simplicity, but if this cannot be done, such as using a .Net v1.1 web service, then you will have to make an exact duplicate of this interface in both flavors of .Net and maintain two separate projects. It sucks, but sometimes if you don't have a choice due to poor code management or a lack of manager foresight you might be stuck in this predicament. One thing to keep in mind is since you are using an older version of .Net for the Interface Library it is important to keep backwards compatibility in mind. So in other words, if you are maintaining a .Net v1.1 interface library and a .Net v4.0 interface library; then it is safer to make your changes in .Net v1.1 and port them over to .Net v4.0. Do NOT go backwards because it can cause very difficult to troubleshoot problems. Just don't do it.
So to recapitulate, the right way to think about this is to think about these projects in pairs... kind of. Lets have two groups:
  • Group A - PublicWebService and RSInterfaceLibrary. Consumer/Client. 
  • Group B - BaseWebApp, RemotingServer and RSInterfaceLibrary. Remoting Server/ Proxy.
Groups A and B speak to each other via the RemotingServer, but must have the RSInterfaceLibrary in common because it is their Contract with each other. This is an implicit concept in Remoting. For WCF it is an explicit concept now, which helps in my opinion. I can't say this enough, MAKE SURE THE INTERFACE LIBRARIES ARE IDENTICAL!

On to the Code. How does this all work?
I like to think of all this as creating pipelines, because essentially that is what this all is. You are creating a tunnel from point A to point B or rather from Group A to Group B. Follow these steps:
  1. Create the BaseWebApp web application project which is in ASP.NET v4.0
  2. Create the PublicWebService web service project which is in ASP.NET v2.0 (or could be .Net v1.1, what ever you require).
  3. Create the RemotingServer class library which is in ASP.NET v4.0
  4. Create the RSInterfaceLibrary class library which is in ASP.NET v2.0. You only need to create one of these projects because .Net v4.0 can take .Net v2.0 as a reference with no problem. If you needed to create one as .Net v1.1, then make two of these projects, one in .Net v1.1 and one in .Net v4.0. You will then have to have two version of visual studio open, which is not a problem, but a little more complicated.
Code Snippets


BaseWebApp
  1. Create a new folder called "BusinessObjects"
  2. Add a new class to it called "BaseObject.cs"
  3. Include the following code:
    public static string UsefulData()
    {
        return "BaseWebApp.BusinessObjects.UsefulData() : " + DateTime.Now.ToString();
    }
    
  4. Host this project in IIS using the same name as the project.

I like returning the current time because it is something that is constantly updating without me having to do it myself and it lets you know if something is working right now.

RSInterfaceLibrary
  1. Take the stock class and rename it to "InterfaceLibrary.cs" (for this example I am not using the proper naming convention of IClassName to be more clear)
  2. Use the following code:
public interface InterfaceLibrary
{
    string GetUsefulData();
}

RemotingServer
  1. Take the stock class and rename it to "Gateway.cs"
  2. Make a project reference or dll reference to the "BaseWebApp.dll"
  3. Make a project reference to the "RSInterfaceLibraray" project
  4. Open "Gateway.cs" and replace the code with this code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaseWebApp.BusinessObjects;

namespace RemotingServer
{
    public class Gateway : MarshalByRefObject, RSInterfaceLibrary.InterfaceLibrary
    {
        public string GetUsefulData()
        {
            return BaseObject.UsefulData();
        }
    }
}

PublicWebService
  1. Make a project reference to the "RSInterfaceLibraray" project
  2. Add a class called "RemotingLogic.cs"
  3. Add the following code to this class:
    public static InterfaceLibrary GetProxyObject()
    {
        string strURL = System.Configuration.ConfigurationManager.AppSettings["remotingServerURL"];
    
        return (InterfaceLibrary)Activator.GetObject(typeof(InterfaceLibrary), strURL);
    }
    
  4. Add the following code to the "Service1.asmx.cs" code behind:
    [WebMethod]
    public string GetUsefulInfoViaRemoting()
    {
        InterfaceLibrary proxy = RemotingLogic.GetProxyObject();
    
        return proxy.GetUsefulData();
    }
    
  5. Host this web service in IIS using what ever name you want.
Configuration Files

  • Client or Consumer Side - You can use this configuration in any kind of consumer that I know of. Web.Config or App.Config. Here is the configuration value for the Web Service side:
    
      
        
      
    
    

    This indicates the direction or location of the remoting server. If you navigate to it you will get an HTTP 500 error, so don't bother it doesn't work that way.
  • Proxy or Remoting Server Side - I have only ever used this configuration with a web application, I don't know what else this could be used with.
    
        
          
            
          
        
     
    

    This is what exposes the remoting server on the web application. It piggy backs off of it, like a parasite on its host.
After implementing all of the above, make sure to compile everything and most importantly for the BaseWebApp and the RemotingServer you need to move the "RemotingServer.dll" and "RSInterfaceLibrary.dll" to the BaseWebApp's bin folder. If you did everything right then this should work right off the bat.

One of the most confusing parts about the configuration is the Web Application's side. Here is the explanation:



I got this information from here: http://social.msdn.microsoft.com/Forums/eu/netfxremoting/thread/cb2681e7-2b06-4dcd-af65-fed5981b93d8

There is ton's more that can be done with this stuff. I recommend that if you are going to have multiple remoting servers for the same application don't bother creating multiple projects, you can just use the same projects and just make sure to configure them properly. Here is an example:


    
      
        
        
      
    


This indicates that you have two additional classes "Gateway2.cs" in the remoting server project and "InterfaceLibrary2.cs" in the interface library project. I used the number 2 just to indicate that it is a second pipeline, but you can call it what ever you want.

Enjoy.

No comments:

Post a Comment