.NET Remoting basics

November 26, 2009

Remoting has been a topic of my interest right from early days of .NET. Here is just an beginner’s tutorial.

1. Whats Remoting?

A: In one line – Interprocess communication in distributed computing.

2. How far distributed?

A: Across the world over internet.

3. Unterstanding remoting from a simple use case?

A: There are 3 parts to the simple use case for remoting:

          a. Remotable object. (Data which travels on the channel)
          b. Host application domain to listen for requests for that object. (Server)
          c. Client application domain that makes requests for that object. (Client)

Lets start with a simple application in Visual Studio…the project will demonstrate a Patient service and remotable Patient objects.

There will be 4 projects

1. Remoting.ClientAccess (Just the interface which the client needs to access the objects on the server)
2. Remoting.ServerObject (Implementation of the interfaces from point 1)
3. RemotingServer (The console application running as server to listen to requests)
4. RemotingTest (The client console application which will make RPCs using the interfaces in point 1)

Project 1 //Remoting.ClientAccess //build it into a library

namespace Remoting.ClientAccess
{
    public interface IPatient
    {
        int PatientCode { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
        int HospitalCode { get; set; }       
    }
}

namespace Remoting.ClientAccess
{
    public interface IPatientService
    {
        void SavePatient(IPatient patient);
    }
}

Project 2 //Remoting.ServerObject // build as a library //reference to project 1

namespace Remoting.ServerObjects
{
    [Serializable]
    public class Patient : System.MarshalByRefObject ,IPatient
    {
        private int ptCode;
        private string fName;
        private string lName;
        private int hospCode;
        #region IPatient Members

        public int PatientCode
        {
            get
            {
                return ptCode;
            }
            set
            {
                ptCode = value;
            }
        }

        public string FirstName
        {
            get
            {
                return fName;
            }
            set
            {
                fName = value;
            }
        }

        public string LastName
        {
            get
            {
                return lName;
            }
            set
            {
                lName = value;
            }
        }

        public int HospitalCode
        {
            get
            {
                return hospCode;
            }
            set
            {
                hospCode = value;
            }
        }
       
        #endregion
    }

}

[Serializable]
    public class PatientService : System.MarshalByRefObject, IPatientService
    {

        #region IPatientService Members

        public void SavePatient(IPatient patient)
        {
            Console.WriteLine(“First name : ” + patient.FirstName);
            Console.WriteLine(“Last name : ” + patient.LastName);
            Console.WriteLine(“Code : ” + patient.PatientCode);
            Console.WriteLine(“Hosp code : ” + patient.HospitalCode);
        }      

        #endregion
    }

Project 3 //RemotingServer // build as a console application //reference to project 1,2

namespace RemotingServer
{
    class Program
    {       
        static void Main(string[] args)
        {
            RemotingConfiguration.Configure(“RemotingServer.exe.config”);
          
            Console.WriteLine(“Press return to exit”);
            Console.ReadLine();
        }
    }
}

Here is the config file which is used in above code:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <system.runtime.remoting>
    <application>
      <service>
        <wellknown mode=”Singleton” type=”Remoting.ServerObjects.Patient, Remoting.ServerObjects” objectUri=”Patient.rem” />
        <wellknown mode=”Singleton” type=”Remoting.ServerObjects.PatientService, Remoting.ServerObjects” objectUri=”PatientService.rem” />
      </service>
      <channels>
        <channel ref=”tcp” port=”8000″>
          <serverProviders>
            <!–provider ref=”wsdl” / –>
            <!–formatter ref=”soap” typeFilterLevel=”Full” /–>
            <formatter ref=”binary” typeFilterLevel=”Full” />
          </serverProviders>
          <!–clientProviders>
            <formatter ref=”binary” />
          </clientProviders–>
        </channel>
      </channels>
    </application>
  </system.runtime.remoting>
</configuration>

Project 4 //RemotingTest // build as a console application //reference to project 1

namespace RemotingTest
{
    class Program
    {
        static void Main(string[] args)
        {
           
            IPatientService ptSvc = (IPatientService)Activator.GetObject(typeof(IPatientService), “tcp://172.16.11.22:8000/PatientService.rem”);
            IPatient pt = (IPatient)Activator.GetObject(typeof(IPatient), “tcp://172.16.11.22:8000/Patient.rem”);
            pt.FirstName = “Vaibhav”;
            pt.LastName = “Gaikwad”;
            pt.PatientCode = 23423 ;
            pt.HospitalCode = 234 ;
            ptSvc.SavePatient(pt);
        }
    }
}

Execute the server application and then execute the client application

Ever thought of getting dynamic web reference from a WSDL? Then making dynamic proxies, and invoking the methods dynamically.

I had some requirement which includes all of the above topics. So after completing my test code I thought of publishing it here for educational purposes.

check it out if you need to do something similar or if you are stuck with some intermediate part:

https://vaibhavgaikwad.wordpress.com/web-services-with-reflection-in-net/

-Bugs!

HL7 v3.0 message handling.

February 12, 2008

Health Level 7 (www.hl7.org) has released version 3.0 for quite a while back, and I have to work on its message handling and integration with health care applications. The new version completely focuses on XML based messages. The Normative Edition comes with a good load of xsds (XML Schema Definition); one for each message type and believe me there are tons of xsds. The message structure has got very much readable and easy to parse using any language which has good xml parser as compared to version 2.x.
The best approach which I can think of for now, is using the xsds do generate classes. I tried to use XSD.exe from the Visual Studio 2005 Tools, but I was unable to fix the reference types. The xsd.exe tool does not take into account the referenced schema definitions, and so I was not able to auto-generate class from those xsd, but when I get that done then I have no big headache. Once the classes are generated, we can just use XmlSerializer class to DeSerialize the xml-message directly to the class and then access the respective properties. Looks simple?

I tried the same trick within a test application which has “shiporder.xml” and “shiporder.xsd”, these files were taken from w3c 🙂
http://www.w3schools.com/schema/schema_example.asp

I created the class using xsd.exe from VS.NET tools, which created “shiporder.cs” for me:
cmd>> xsd shiporder.xsd /c

Then I build a simple and sweet standalone application to test it.
//code c#
using System.IO;
using System.Xml.Serialization;
namespace XSDTest
{
class Program
{
static void Main(string[] args)
{

// shiporder.cs
XmlSerializer serial = new XmlSerializer(typeof(shiporder));
TextReader reader = new StreamReader(“shiporder.xml”);

// this is how you directly get the data back.
shiporder so = (shiporder) serial.Deserialize(reader);

}
}
}
//end code
 

I hope I will be able to resolve the reference schemas in the HL7 xsds, and then build the classes out of it in near future, till then try out other possible methods 🙂 -Bugs

If you are playing with XML using .NET libraries, then you might be familiar with below mentioned exception:
System.Xml.XPath.XPathException: ‘objOfXmlDocument[@attribute={value containing single-quote}]’ has an invalid token.
If you are looking for a patch for the above mentioned problem, then you are at the right place.
Sample xml text: //test.xml
<?xml version=”1.0″ encoding=”utf-8″ ?>
<
root>
<
emp fname=”Vaibhav” lname=”Gaikwad” />
<
emp fname=”Lavina” lname=”D’cunha” />
</
root>
//code to access the test.xml
class
Program
{
static void Main(string[] args) {
XmlDocument doc = new XmlDocument();
doc.Load(
“test.xml”);
string ln =
“D’cunha”;
// This fails :((  resulting in XPath exception.
XmlNode n = doc.SelectSingleNode(“/root/emp[@lname=’ “+ ln +” ‘]”);
}
}  
So, the issue is due the single-quote inside the XPath expression.
We try to resolve it using the “concat” function of XSL, and this is the helper function:
public static string GetXPathString(string input) {
string[] fragments = input.Split(new char[] { ‘\” });
string result = “”;
result += “concat(””;
for (int i = 0; i < fragments.Length; i++)
{
result += “, ‘” + fragments[i] + “‘”;
if (i < fragments.Length – 1)
{
result += “, \”‘\””;
}
}
result += “)”;
return result;
}
And here is how you modify the above code so as to use our new function:
// remember to remove the single-quotes after = and ]
 
XmlNode n = doc.SelectSingleNode(“/root/emp[@lname=” + GetXPathString(ln) + “]”);
So its all done and the day is saved.

 -Bugs!

Recently I got a comment on my last post that it was throwing up exceptions. I realised the bad things in the code. Here is the revised version of the same

// CLSID_CorRuntimeHost from MSCOREE.DLL

[ Guid(“CB2F6723-AB3A-11D2-9C40-00C04FA30A3E”), ComImport]
class CorRuntimeHost {}

// IID_IcorThreadPool  

[ Guid(“84680D3A-B2C1-46e8-ACC2-DBC0A359159A”),InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICorThreadpool {
// Note that IUnknown Interface members are NOT listed here:
void RegisterWaitForSingleObject();
void UnregisterWait(); 

void QueueUserWorkItem();
void CreateTimer(); 
void ChangeTimer(); 
void DeleteTimer(); 
void BindIoCompletionCallback(); 
void CallOrQueueUserWorkItem();
void SetMaxThreads(uint MaxWorkerThreads, uint MaxIOCompletionThreads);
void GetMaxThreads(out uint MaxWorkerThreads, out uint MaxIOCompletionThreads);
void GetAvailableThreads(out uint AvailableWorkerThreads, out uint AvailableIOCompletionThreads);}

//Here is the sample code for the consumption of these types. CorRuntimeHost runtimeMgr = new CorRuntimeHost();
// QueryInterface for the ICorThreadPool interface
ICorThreadpool coreThreadPool = (ICorThreadpool)runtimeMgr;
uint maxWorkerThreads;
uint maxIOThreads;
coreThreadPool.GetMaxThreads(
out maxWorkerThreads, out maxIOThreads); // this returned me 50, 1000
coreThreadPool.SetMaxThreads(25,1000); //setting max of 25 threads

//end code

This code is tested on .NET 2.0, and if you face any issues for 1.0 or 1.1 please let me know.-Bugs!

.NET ThreadPool has a default maximum number of threads in pool which is 25 as documented. There might be a need to increase it, but there is no proper documented API to achieve this goal. This might be a requirement for many of us.

Here’s what you can do:

The Mscoree.h has the definitions for MAX limit of thread pool, and there are APIs for getting/setting it.

What is Mscoree.dll?
Mscoree.dll is the .NET Runtime Execution Engine.

So how can you change the default size of ThreadPool?
Using the definitions in Mscoree.h we can define a COM interop dll, as mentioned below
using System;
using System.Runtime.InteropServices;
[Guid(“CB2F6723-AB3A-11D2-9C40-00C04FA30A3E”), ComImport]
class CorRuntimeHost {}

[Guid(“84680D3A-B2C1-46e8-ACC2-DBC0A359159A”),InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ICorThreadPool
{
void slot0(); // max threadpool settings
void slot1();
void slot2();
void slot3();
void slot4();
void slot5();
void slot6();
void CorSetMaxThreads( uint MaxWorkerThreads, uint MaxIOCompletionThreads );
void CorGetMaxThreads( out uint MaxWorkerThreads, out uint MaxIOCompletionThreads );
void CorGetAvailableThreads( out uint AvailableWorkerThreads, out uint AvailableIOCompletionThreads );
}
// Ok you are done with the COM interop, now build this into a class library (e.g. ThreadPool.dll )

Then you must consume the dll into you application, and using the APIs of this managed dll you can now change the default ThreadPool size. Here how you go about doing it.

uint maxWorkerThreads;
uint availWorkerThreads;
uint maxIOThreads;
uint availIOThreads;

ICorThreadPool iThreadPool ;
iThreadPool = (ICorThreadPool)new CorRuntimeHost();
iThreadPool.CorGetMaxThreads(out maxWorkerThreads, out maxIOThreads);
iThreadPool.CorGetAvailableThreads(out availWorkerThreads, out availIOThreads);
System.Console.Writeline(“Available worker threads : ” + availWorkerThreads);
System.Console.Writeline(“Available IO threads : ” + availIOThreads);
iThreadPool.CorSetMaxThreads(30,availIOThreads); // changing worker threadpool size from 25 to 30

Hmm! so we are done 🙂

-Bugs!

This article discusses how web services are generated on the fly. The code is generated and compiled at runtime. The code file  (i.e. “.cs”), service file (i.e. “.asmx” ) and compiled library (i.e. “.dll”) are generated dynamically.

After this code generation the third party applications can directly add a web-reference to the respective web-service and start using it.

class extenstions
    {
        public const string asmx = “.asmx”;
        public const string cs = “.cs”;
        public const string dll = “.dll”;
    }  #region WebService on Fly
string binPath = @”D:\StudioProjects\wwwroot\bin\”;
string codePath = @”D:\StudioProjects\wwwroot\code\”;
string asmxPath = @”D:\StudioProjects\wwwroot\webservices\”;
string code = “[WebService(Namespace = \”http://tempuri.org/\”)] “ +
              “[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]” +
              “public class dyna : System.Web.Services.WebService “ +
              “{ “ +
              “public dyna () {} “ +
              “[WebMethod]” +
              “public string HelloWorld() { “ +
              “return \”Hello World\”; “ +
              “}” +
              “}”;
string classname = “dyna”;
string[] assemblies = new string[] {
     “System”,“System.Web”,“System.Web.Services”,“System.Web.Services.Protocols”
};
 
//CS file generation
string codeFile =  codePath + classname + extenstions.cs;
StreamWriter writer = new StreamWriter(codeFile ,false);
foreach(string assembly in assemblies)
writer.WriteLine(“using “ + assembly + “;”);
writer.WriteLine();  
writer.Write(code);
 
writer.Close();
// ASMX  file generation
string asmxCode = “<%@ WebService Language=\”C#\” CodeBehind=\”~\\code\\”
+ classname + extenstions.cs +
“\” Class=\”” + classname + “\” %> “;
writer = new StreamWriter(asmxPath + classname + extenstions.asmx,false);
writer.WriteLine(asmxCode);
writer.Close(); 
Microsoft.CSharp.CSharpCodeProvider provider = new Microsoft.CSharp.CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler(); 
CompilerParameters param = new CompilerParameters();
param.CompilerOptions = @”/optimize”;
param.GenerateInMemory = false;
param.GenerateExecutable = false;
param.IncludeDebugInformation = false;
param.TreatWarningsAsErrors = false;
param.ReferencedAssemblies.Add(“System.dll”);
param.ReferencedAssemblies.Add(“System.Web.dll”);
param.ReferencedAssemblies.Add(“System.Web.Services.dll”);
param.OutputAssembly = binPath + classname + extenstions.dll;
CompilerResults results = compiler.CompileAssemblyFromFile(param, codeFile);
if (results.Errors.Count > 0)
{
StringBuilder err = new StringBuilder(); 
int i=1;
           
foreach (CompilerError error in results.Errors)
{
err.AppendLine(i + ” : “ + error.ErrorText);
err.AppendLine();
}
 
throw new Exception(err.ToString());
}
#endregion 

Now you can test your web-service directly on the local machine using a url. And the client application can directly include a web-reference to your web-service dll in the “webservices” directory of my application.

Incase you get a error saying “401 Access Denied” then just enable “Anonymous access” & “Intergrated Windows aunthentication” on the “webservices” folder.

 

-Bugs!