Click here to Skip to main content
Click here to Skip to main content

TCP Remoting Windows Service Host with Server GC

, 14 Apr 2004 CPOL
Rate this:
Please Sign up or sign in to vote.
Implement Server GC for TCP Remoting Host.

Introduction

The Server Side published a beta version of "Improving .NET Application Performance and Scalability" by Microsoft Pattern and Practice Group. In chapter 8 about remoting, Windows Service Host for remoting is labeled not optimized since it uses Workstation GC (Garbage Collection). Also according to Gregor Noriskin in this article: "The Server GC is optimized for throughput and multi-processor scalability" and "If you are building a server application that is going to run on multiprocessor machines then it is highly recommended that you use the Server GC".

This article intends to implement a TCP Remoting Host with Server GC. The source code is included for developers in this community to comment and improve. I will try to explain step by step how this host is built, and hopefully generate some interest in writing a truly scalable TCP Remoting Host.

This article primarily targets developers with C# and .NET Framework experience (Remoting). The usage of ATL is at beginner level and is for the sole purpose of creating CLR host.

How to specify Server GC

Server GC has to be specified before AppDomain gets loaded and user code gets executed. So we will have to use unmanaged code. The following is the API from MSDN documentation to do just that:

HRESULT hr = 
CorBindToRuntimeEx(pszVer, pszFlavor, Flags, CLSID_CorRuntimeHost, 
IID_ICorRuntimeHost, (void **)&pHost);

According to this article, pszFlavor = "svr" for CLR Server Build and "wks" for CLR workstation build, and CLR Server build is designed to use multiple processors and is more scalable. As for Flags, STARTUP_CONCURRENT_GC stands for Concurrent GC, and everything else stands for non-concurrent GC. Non-concurrent GC does collection on the same thread as user code, and the server application would be less responsive to a particular request to execute user code, but overall GC Collection performs better. Therefore, for TCP Remoting host that runs as Server Application, I chose to use the API as follows:

LPWSTR pszVer = L"v1.1.4322";
LPWSTR pszFlavor = L"svr";
ICorRuntimeHost *pHost = NULL;  
// this is changed to a global unmanaged variable in download code

HRESULT hr = CorBindToRuntimeEx(pszVer, pszFlavor,  
STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN, CLSID_CorRuntimeHost, 
IID_ICorRuntimeHost, (void **)&pHost);

Clearly, I have defined Server GC as "CLR Server Build with non-concurrent GC" and I believe Server GC has better scalability and can utilize multiple CPU better.

How to get to Default AppDomain:

After creating CLR Host as above, we need to access its default AppDomain to load our Remoting host code. In fact, all managed code must reside in an AppDomain, and Default AppDomain for the CLR Host is the easiest choice:

pHost->Start();
mscorlib::_AppDomain *pDefaultDomain = NULL;
IUnknown   *pAppDomainPunk = NULL;

hr = pHost->GetDefaultDomain(&pAppDomainPunk);
hr = pAppDomainPunk->QueryInterface(__uuidof(mscorlib::_AppDomain), 
                                      (void**) &pDefaultDomain);

Notice that pDefaultDomain is a COM Pointer type from mscorlib.tlb and it allows us to get access to the Default AppDomain from the unmanaged CLR Host. Next, we transit into managed code and load our managed remoting hosting code into this Default AppDomain as follows:

JQD::RemoteObjectLoader *pRemotingHost=NULL;
mscorlib::_ObjectHandle *pObjHandle = NULL;
hr = pDefaultDomain->CreateInstance(_bstr_t("RemoteObjectLoader"), 
                                 _bstr_t("JQD.RemoteObjectLoader"),       
                                  &pObjHandle); 

VARIANT v;
VariantInit(&v);
hr = pObjHandle->Unwrap(&v);
hr =v.pdispVal->QueryInterface(
                     __uuidof(RemoteObjectLoader::_RemoteObjectLoader), 
                    (void**) &pRemotingHost);
pRemotingHost->Load();

Notice that pointer to default AppDomain creates an instance of a managed object with a unmanaged handle, which can be unwrapped and cast into a managed pointer pRemotingHost. This pointer could execute the following C# code:

   public class RemoteObjectLoader
     {
      public void Load()
       {
         ChannelServices.RegisterChannel(new TCPChannel(10002));
     RemotingConfiguration.RegisterWellKnownServiceType(
            typeof (JQD.MyClass),
        "MyClassURI", WellKnownObjectMode.SingleCall);
       }
     }

This completes the starting of TCP Remoting using Server GC. As illustrated in the following diagram, this process utilizes both managed and unmanaged code to build the CLR host and eventually load Remoting Hosting code

Diagram for CLR Host

Finally, I have hard coded Remote classes in Load() for illustration. In real world applications, you would use RemotingConfiguration.Configure to expose your objects, and that is what I did in the sample download.

How to run the sample code:

After downloading the zip file, extract it to a directory such as c:\working\CLRMHost. You need to do the following few things:

  • Open the solution (clrmhost.sln) and compile the release build.
  • Copy MyClass.dll from MyClass\Bin\Release to CLRMHost\release.
  • In a Command prompt, change to CLRMHost\Release and type "CLRMHost.exe -i" (this will install the service).
  • If you wish to uninstall the service, run CLRMHost\uninstall.vbs.
  • Open Services MMC and start the service "TCPRemotingHostServerGC".
  • Type http://localhost:10000/MyClassTCPURI?wsdl in IE Browser and you should see WSDL document as a test. You can then write a TCP Remoting client against port 10003 to test TCP Channel.

Some important details

This .NET Solution consists mainly of two projects: a C++.NET Windows Service Project and a Remoting Loader .NET Class Library Project. All unmanaged C++ code resides in the Windows Service Project, which has included important header file mscoree.h for accessing CorBindToRuntimeEx, etc., and atlbase.h for accessing ATL. Furthermore, mscorlib.tlb and RemoteObjectLoader.tlb are imported for transition from unmanaged process to managed code. RemoteObjectLoader.tlb can be generated by command "tlbexp". Note that there is a bug where Config file for Windows Service exe does not get copied to release or debug directory upon compilation. So I have utilized BaseDirectory property for AppDomain to set Remoting Configuration file path instead. Finally, installUtil.exe cannot be used to install this particular Windows Service since that service contains unverifiable C++ unmanaged code. Fortunately, C++ IDE generated code to do installation as "CLRMHost.exe -i". Still to uninstall, you have to run the included VB Script file uninstall.vbs. This script uses WMI to delete the Windows Service "TCPRemotingHostServerGC".

Conclusion

This article provides a reasonably complete implementation for TCP Remoting host using Windows Service and Server GC. Anyone can just download it and add your own object for TCP remoting. Although it does not have proven scalability like IIS hosted HTTP Remoting, overtime developers in this community should be able to get a concrete and real understanding of TCP remoting host, and improving its scalability and throughput.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

jqd2001
Web Developer
United States United States
I am a Microsoft Certified Application Developer (MCAD), currently focusing on using .Net Framework to develop Business Solutions. I am mostly language neutral. I have used C, C++, ATL, MFC, VB.Net, C#, VB 6, PL/SQL, Transact SQL, ASP, Fortran, etc.

Comments and Discussions

 
GeneralResearch Pinmemberdpswe20-May-04 5:47 
GeneralRe: Research PinmemberSaaandy19-Aug-04 22:52 
GeneralRe: Research Pinmemberjamesqding23-Aug-04 8:35 
GeneralRe: Research PinmemberKraGiE7-Apr-05 17:51 
James is correct in that using VB 6.0 to load up all the necessary runtimes for running .net applications is not a good solution. In fact, the amount of pure vb6 code that it would require would leave a lot of room for errors, and VB 6 error handling isn't as refined as the stack dumps of .NET
 
Your best bet is to read this article, and learn how to register your .net assemblies to be exposed through the COM interface.
 
http://www.vbrad.com/pf.asp?p=source/src_real_interop.htm
 
It's not the best article, but it goes over the top rather nicely and without fluff. I like articles like that because it's precise, and it works on the first try.
 
------------
 
James,
 
I've spent the past few days researching the current articles on remoting with .NET because I'm thinking of publishing a new article on aspalliance that will involve remoting and even binary serialization. With your article, I noticed that it lacked benchmarks or even some calculations of memory usage. Is the idea that it will assist in performance and maybe scalability in the future just a theory or have you taken the time to test the differences? I'm definitely not going to rip your article, and I'm actually overly anal about referencing where I got the information I didn't know ahead of time.
 
It intriged me, and I haven't downloaded the source yet. I'll take a look at it over the weekend, and definitely get back to you with a more calculated opinion. However, I do wish to verbalize that your article definitely caught my attention rather quickly, and I'm actually reading it. Smile | :) So thanks for taking the time in writing the article. I know it can be a chore after the initial zeal wears off.
 

 
Kay Lee
Managing Partner
Evans & Lee Technologies LLC
-------------------------------
http://aspalliance.com/author.aspx?uId=51561
http://www.windowsforms.net/forums
GeneralRe: Research Pinmemberjamesqding11-Apr-05 5:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.1411023.1 | Last Updated 15 Apr 2004
Article Copyright 2004 by jqd2001
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid