.NET Remoting

The Alternative to Web Services

Ken McNamee

October 30, 2009

12 Min Read
ITPro Today logo

asp:coverstory

LANGUAGES: C#

.NET VERSIONS: 1.1

 

.NETRemoting

TheAlternative to Web Services

 

By KenMcNamee

 

You'reprobably familiar with the idea of using ASP.NET Web services for remotecommunication between applications. Web services are especially useful forinteroperation between different platforms, such as a Java client making a callto an ASP.NET Web service.

 

Webservices do have their drawbacks, however, and aren't the best option in somecases. For instance, .NET Remoting may be a better option when both the clientand the server are running on the .NET Framework. One of the main issues with aWeb service is the overhead involved when the request and response need to beconverted back and forth between binary and XML. If you've ever tried to do XMLserialization, you know that the performance cost isn't trivial.

 

The goodnews - at least for those of us lucky enough to be using .NET on both ends of aremote procedure call - is that .NET Remoting doesn't suffer from the XMLserialization performance hit - unless you want it to. Like an ASP.NET Webservice, which has multiple encoding options, .NET Remoting offers more thanone communication format. There's HTTP SOAP, which is roughly equivalent to aSOAP Web service, including the performance hit due to serialization. Thenthere is HTTP Binary, which, of course, also communicates over the standardInternet protocol. However, the communication format remains binary, thusbypassing the performance problem of SOAP. There is a small performance hit assome serialization to a .NET proprietary format takes place, but it's animprovement over SOAP.

 

Finally,there's the TCP Binary option, which is as close to the metal as .NET gets outof the box. TCP Binary is the fastest option that .NET Remoting offers, andit allows for the most flexibility. At the same time, it provides less built-infunctionality than HTTP SOAP or HTTP Binary. One of the major benefits of thoseoptions is that they are hosted by an ASP.NET Web server. This point cannot beoverstated. ASP.NET is a very deep platform on which to build an application,even one that doesn't serve up any Web pages, and you would be hard-pressed toduplicate its functionality with your own TCP Binary server.

 

For thisreason, the code sample on which this article is based (see end of article fordownload details) uses HTTP Binary as the communication mechanism. Later in thearticle I'll go into the pros and cons of each Remoting option. However, as ageneral rule I believe that HTTP Binary is the best option because of thebetter performance than SOAP, and the wealth of functionality at your disposalby using the ASP.NET platform. There are certainly valid reasons to choose HTTPSOAP or TCP Binary, but it would be hard to go wrong with HTTP Binary as your startingpoint.

 

The Basics

At aminimum, a .NET Remoting application consists of a remotely callable object, aserver process to host the object, and a client process that makes the call tothe object. Additionally, the application will more than likely also consist ofone or more serializable classes that are passed through the Remoting frameworkbetween client and server. This setup is what almost all .NET Remotingapplications will have in common.

 

One ofthe surprising discoveries I made while learning to use Remoting is how easy itis to create production-ready applications. It's almost as easy as creating aWeb service. To start with, the remotely callable object is very simple toimplement. Just have your class inherit from MarshalByRefObject, which enablesthe object to be used as an endpoint for a remote procedure call. As far as theobject goes, that's all you have to do. Unlike Web services, you don't need tomark each method as a remote method. As long as the object inherits from MarshalByRefObject,all public methods will be accessible to remote clients - providing that theclients know the URL, and can successfully get past any authentication.

 

The CodeSample

The codesample described in and accompanying this article is an interface for managingthe Products table in the Northwind database, and consists of three projects.First is the server project that hosts the remote object as an ASP.NET Webapplication. Second is the client project that communicates with the server.The third is something I haven't yet discussed: a class library project thatcontains common classes that are shared by the client and the server projects.

 

The SharedAssembly

Thepurpose of using a shared assembly is to prevent the client project fromneeding a direct reference to the server project, or vice versa. This providesa clean and logical separation between the two tiers without the danger ofcreating a circular reference. In this simple example, the shared assemblycontains two types of objects: classes that encapsulate and transport data suchas the Product class, and interfaces that the client can use to makecalls to the actual remote objects.

 

The Productclass displayed in Figure 1 encapsulates the Products table, and exposes itscolumns as .NET properties. Because it's marked with the Serializableattribute, the Product class can be used as a lightweight datacontainer, and can be sent through the .NET Remoting transport mechanismbetween client and server.

 

[Serializable]

public classProduct

{

  // Member variables.

  ...

 

  // Constructors.

  public Product()

  {

    _supplier = new DictionaryItem();

    _category = new DictionaryItem();

  }

 

  // Properties.

  public int ProductID { get {...} set {...} }

  public string ProductName { get {...} set{...} }

  public DictionaryItem Supplier { get {...}set {...} }

  public DictionaryItem Category { get {...}set {...} }

  public string QuantityPerUnit  { get {...} set {...} }

  public decimal UnitPrice { get {...} set{...} }

  public int UnitsInStock { get {...} set{...} }

  public int UnitsOnOrder { get {...} set{...} }

  public int ReorderLevel { get {...} set{...} }

  public bool Discontinued { get {...} set{...} }

}

Figure1: The Productclass encapsulates the Products table in the Northwind database and serves as aserializable transport container.

 

The ProductSearchCriteriaclass (see Figure 2) serves as the container for users' search criteria - inthis case the product ID and the product name. In addition, it contains onehelper method (ToWhereClause) that converts the search criteria into theWHERE clause that will be used in the SQL statement that executes the search ofthe Products table. This logic could just as easily go into the Web service,but I chose to put it here.

 

[Serializable]

public classProductSearchCriteria

{

  // Member variables.

  ...

 

  // Constructors.

  public ProductSearchCriteria() {}

 

  // Properties.

  public int ProductID { get {...} set {...} }

  public string ProductName { get {...} set{...} }

 

  // Public methods.

  public string ToWhereClause()

  {

    StringBuilder stringBuilder = newStringBuilder();

 

    if (_productID > 0)

      stringBuilder.Append("(Products.ProductID = " +

        _productID.ToString() + ")");

    else if (_productName.Trim() !=string.Empty)

      stringBuilder.Append(" (Products.ProductName LIKE '" +

        _productName + "%') ");

   

    if (stringBuilder.Length > 0)

      stringBuilder.Insert(0, "WHERE");

     

    return stringBuilder.ToString();

  }

}

Figure2: The ProductSearchCriteriaclass contains the fields that a user can use to search the Products table.

 

The lastitem of note in this project is the IProductManager interface. Thepurpose of this interface is to allow the actual remote object on the server tobe abstracted away from the client. The client will not be aware of the ProductManagerremote object that's being hosted by ASP.NET on the server. It will only knowabout the interface in the Shared assembly, what methods it contains, and whattheir signatures are.

 

The Server

TheServer project is like any other ASP.NET Web application, except for a fewdifferences:

  • Itdoesn't need to contain any Web pages or Web services.

  • To bea Remoting host it must contain at least one class that inherits from MarshalByRefObject.

  • TheWeb.config file must contain a special sectionthat tells ASP.NET which remote objects to expose and what their URL filenamewill be.

  • TheServer project must have a reference to the System.Runtime.Remotingassembly and the Shared Project.

 

Althoughthe Web application doesn't need to contain any Web pages, there's nothingstopping you from adding some. .NET Remoting objects and ASP.NET Web forms canco-exist quite nicely within the same Web application. In fact, there are caseswhere this would be preferable, such as hosting the "help" Web pages or atutorial for the Windows Forms client.

 

Thefirst task is to create the remote object class, which is ProductManagerin this example. You can see part of this class in Figure 3. The ProductManagerclass inherits from MarshalByRef, which provides it with the status of remotableobject. However, the class also implements the IProductManagerinterface, which means that it must implement all the methods of thatinterface. One method shown in Figure 3 is GetProductList. This methodtakes a ProductSearchManager object as its sole parameter and returns anarray of Product objects. The ToWhereClause method of the ProductSearchManagerobject is used to complete the SQL statement that searches the Product table,and returns only the products matching the user's criteria.

 

public classProductManager :

  MarshalByRefObject, IProductManager

{

  public Product[] GetProductList(

    ProductSearchCriteria searchCriteria)

  {        

    string sql = "SELECT " +"Products.ProductID, " +

      "Products.ProductName, " +"Products.SupplierID, " +

      "Suppliers.CompanyName, " +"Products.CategoryID, " +

      "Categories.CategoryName, " +

      "Products.QuantityPerUnit, " +

      "Products.UnitPrice, " +"Products.UnitsInStock, " +

      "Products.UnitsOnOrder, " +

      "Products.ReorderLevel, " +"Products.Discontinued "+

      "FROM " + "Products" + "LEFT OUTER JOIN " +

      "Suppliers ONSuppliers.SupplierID=" +

      "Products.SupplierID " +"LEFT OUTER JOIN " +

      "Categories ONCategories.CategoryID=" +

      "Products.CategoryID " +

      searchCriteria.ToWhereClause() + "" +

      "ORDER BY " +"Products.ProductName";

    

    DataTable dataTable =SqlHelper.GetDataTable(sql);

    Product[] products = newProduct[dataTable.Rows.Count];

    

    for(int i = 0; i     products[i] =InitProduct(dataTable.Rows[i]);          return products;   } }Figure3: The ProductManagerclass is the object that can be called from the remote client. Inheriting fromthe MarshalByRef class gives it this ability.   So youcan see that there is really nothing special about a remotable object class.Other than inheriting from MarshalByRef, you develop the class just asany other class. One more thing to note about this class is that it isn'trestricted to being called only from remote clients. Any other code that cansee the ProductManager class can call one of its public methods. Oneoption here is to create a Web service that internally calls the ProductManagermethods. This would come in handy if you wanted internal, .NET clients to usethe Remoting objects and external, non-.NET clients to use the Web service. Youcould concentrate all your business logic into the remote object and not haveto duplicate it in the Web service.   Youmight be thinking, "How does the client call the remote object if there's noWeb page or Web service to complete a URL?" This is where the Web.config filecomes in. You need to add some configuration information to fake a URL, whichyou can see demonstrated in Figure 4.                         type="CodeSample.Server.ProductManager,                CodeSample.Server"         objectUri="ProductManager.rem"/>                                                                         Figure4: The web.configfile needs some configuration settings to provide the remote object with a fakeURL for the client to call.   The keynode in the section is the node. The type attribute points to the fully qualified class name and theassembly in which to find it. The objectUri attribute is the resourcename that you want to assign the remote object in the URL. So the node in this case configures the CodeSample.Server.ProductManagerclass in the CodeSample.Server assembly to have a resource name ofProductManager.rem. The extension that you give in the objectUri isimportant. It can be almost anything you like, as long as it doesn't conflictwith another extension that is already mapped to the ASP.NET ISAPI DLL. Thereare two extensions set aside for Remoting when you install the .NET Framework:.rem and .soap. It's preferable that you use one of these two extensions.   The Client The actualimplementation of the Remoting client isn't important. What is important is thecode for calling a remote object. Unlike Web services, you don't need to add aWeb Reference or create a proxy object to use .NET Remoting on the client. Youonly need a few pieces of information: TheURL of the remote object. Thetype of the remote object, or the interface that the remote object implements. Whatthe communication protocol will be (HTTP or TCP) and what the format of thecommunication will be (SOAP or Binary).   The onlyother step you need to take is to make sure that, like the server project, yourclient references the System.Runtime.Remoting assembly and the Sharedproject. As displayed in Figure 5, the code for calling a remote object'smethods is not exactly intuitive. In fact, there are a couple of ways toaccomplish the task: programmatically, and by using a configuration file.Figure 5 displays the programmatic method.   privateIProductManager GetIProductManager(){  string objectUri="http://domain/vdir/ProductManager.rem";     HttpClientChannel httpBinaryChannel =    newHttpClientChannel("HttpBinary",       newBinaryClientFormatterSinkProvider());  try {    ChannelServices.RegisterChannel(httpBinaryChannel);   } catch {}    return Activator.GetObject(typeof(IProductManager),     objectUri); }  private voidbtnSearch_Click(object sender, EventArgs e) {  //..construct searchCriteria  Product[] products = GetIProductManager().    GetProductList(searchCriteria); }Figure5:Programmatically calling a remote object is not very intuitive, but it willmake sense - eventually.   Remotingworks using the concept of channels, which the .NET Framework uses to transportthe request to the ASP.NET runtime on the server. In this case, we're using an HttpClientChanneland initializing it as HttpBinary in its constructor. Next, the channelmust be registered by the ChannelServices object. Lastly, we call Activator.GetObjectand pass in the type we're trying to activate and the URL where it can befound. The GetIProductManager method returns an instance that matchesthe IProductManager interface, which enables the GetProductListmethod to be called. You can encapsulate most of this plumbing code into ahelper class library, so that your regular form code can call remote methods aseasily as a local method.   SOAP orBinary or TCP? Likealmost all programming decisions, which .NET Remoting option you choose reallydepends on your specific project and the importance of performance versusmaintainability, project completion speed, and security. I've already stated mypreference for HTTP Binary, which is where I always start.   Ifperformance is of the utmost importance, your best - and usually only - optionis TCP Binary. This will allow for the fastest possible communication betweenclient and server with an absolute minimum of overhead on either end. You candevelop your own encryption and authentication methods to use if ASP.NETdoesn't suit your needs. Another key difference between the TCP and HTTPoptions is that you can choose which ports to use on the client and the server.With HTTP, IIS chooses the ports.   Conclusion.NETRemoting is a useful technology to learn. Although newer and betterinter-application communication technologies are on the way from Microsoft, Remotingis here now and should at least be considered when the client and server areboth based on .NET. Granted, it will never overtake Web services in flexibilityand popularity. However, as you have seen, .NET Remoting can be just as simpleto develop as Web services, and it offers a few options that Web services doesnot.   Resources.NETRemoting FAQ: http://www.ingorammer.com/RemotingFAQ/   The sample code accompanying this article is availablefor download.   KenMcNamee is aSenior Software Developer with Vertigo Software, Inc., a leading provider ofsoftware development and consulting services on the Microsoft platform. Priorto this, he led a team of developers in re-architecting the Home ShoppingNetwork's e-commerce site, http://www.HSN.com,to 100% ASP.NET with C#. Readers can contact him at [email protected].      

Read more about:

Microsoft
Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like