Dailycode.info

Short solution for short problems

Migrating remoting to WCF

WCF is the sequal for .Net remoting and web services. Its a very powerfull and helpfull strategy. Finally we can forget about all the different implementations and simply use WCF. Configure if you need the TCP or http protocol, Message queue ... . This is great. I started to migrate the LIMS system that uses both Remoting and Web services. The webservices are still to come, but I don't expect problems. The remoting is a different story. Since remoting supports overloading and WCF doesn't, you can rewrite a lot of code and revise all code that consume you're remoting functions.

So the first thing that came up was to get rid overloaded functions by renaming them after their parameters.

This covered most of the work. Then some strange hard to debug error poped up. All my objects had the [DataContract] and [DataMember] defined, but I forgot that enums need a [DataContact] and [EnumMember]. You will need to define the [EnumMember] for each value in the enum. For Example:

After some configuration and the creation of the Channel factory on the client, I got the whole thing to work. Here is the code of the channelfactory implementation:

      /// <summary>
      /// Describes the different types of hardware
      /// </summary>
    [DataContract]
    public enum DeviceTypeEnum
      {
        [EnumMember]
            Plexx = 1,                    //    Plexx RF reader
        [EnumMember]
        Sartorius,                        //    Sartorius Balance
        [EnumMember]
        Mettler,                    //    Mettler Toledo Balance
        [EnumMember]
        MBBS,                             //    MBBS ISO Reader
        [EnumMember]
        Opticon,                    //    Opticon barcode reader
        [EnumMember]
        AllFlex                           //  Allflex RFID reader
      }

 

using System;
using LabCollect.ServerComponents.SharedClasses;
using Deraeve.Connections;
using LabCollect.ServerComponents.Service;
using System.ServiceModel;
 
namespace LabCollect.SmartclientFrame.SubApplications
{
    /// <summary>
    /// Summary description for LabCollectRemotingFactory.
    /// </summary>
    public class LabCollectChannelFactory : IDisposable
    {
 
        // Remoting Object Factory
        private IAnimalManager _animalMgrProxy;
        private IConfigurationManager _configMgrpProxy;
        private IStudyManager _studyMgrProxy;
        private IUserManager _userMgrProxy;
 
        string animalEndPoint = "http://localhost:.../AnimalMgr";
        string configEndPoint = "http://localhost:.../ConfigurationMgr";
        string studyEndPoint = "http://localhost:.../StudyMgr";
        string userEndPoint = "http://localhost:.../UserMgr";
 
        public IAnimalManager AnimalManager
        {
            get 
            {
                if ((_animalMgrProxy as ICommunicationObject).State != CommunicationState.Opened)
                {
                    _animalMgrProxy = ChannelFactory<IAnimalManager>.CreateChannel(
new WSHttpBinding(), new EndpointAddress(animalEndPoint));
                }
                return _animalMgrProxy;
            }
        }
 
        public IConfigurationManager ConfigurationManager
        {
            get 
            {
                if ((_configMgrpProxy as ICommunicationObject).State != CommunicationState.Opened)
                {
                    _configMgrpProxy = ChannelFactory<IConfigurationManager>.CreateChannel(
new WSHttpBinding(), new EndpointAddress(configEndPoint));
                }
                return _configMgrpProxy; 
            }
        }
 
        public IStudyManager StudyManager
        {
            get 
            { 
                if ((_studyMgrProxy as ICommunicationObject).State != CommunicationState.Opened)
                {
                    _studyMgrProxy = ChannelFactory<IStudyManager>.CreateChannel(
new WSHttpBinding(), new EndpointAddress(studyEndPoint));
                }
                return _studyMgrProxy; 
            }
        }
 
        public IUserManager UserManager
        {
            get 
            {
                if ((_userMgrProxy as ICommunicationObject).State != CommunicationState.Opened)
                {
                    _userMgrProxy = ChannelFactory<IUserManager>.CreateChannel(
new WSHttpBinding(), new EndpointAddress(userEndPoint));
                }
                return _userMgrProxy; 
            }
        }
 
        public void InitChannels()
        {
            _animalMgrProxy = ChannelFactory<IAnimalManager>.CreateChannel(
new WSHttpBinding(), new EndpointAddress(animalEndPoint));
            _configMgrpProxy = ChannelFactory<IConfigurationManager>.CreateChannel(
new WSHttpBinding(), new EndpointAddress(configEndPoint));
            _studyMgrProxy = ChannelFactory<IStudyManager>.CreateChannel(
new WSHttpBinding(), new EndpointAddress(studyEndPoint));
            _userMgrProxy = ChannelFactory<IUserManager>.CreateChannel(
new WSHttpBinding(), new EndpointAddress(userEndPoint));
        }
 
        #region IDisposable Members
 
        public void Dispose()
        {
            if ((_animalMgrProxy as ICommunicationObject).State == CommunicationState.Opened)
            {
                (_animalMgrProxy as ICommunicationObject).Close();
            }
 
            if ((_configMgrpProxy as ICommunicationObject).State == CommunicationState.Opened)
            {
                (_configMgrpProxy as ICommunicationObject).Close();
            }
 
            if ((_studyMgrProxy as ICommunicationObject).State == CommunicationState.Opened)
            {
                (_studyMgrProxy as ICommunicationObject).Close();
            }
 
            if ((_userMgrProxy as ICommunicationObject).State == CommunicationState.Opened)
            {
                (_userMgrProxy as ICommunicationObject).Close();
            }
        }
 
        #endregion
    }
}

 

Next challange will be implementing apropriate error handling and also I want to change the audit function to use MessageQueue combined with WCF.

I'll keep you updated on this and have some snippits ready.

 

 

 


Generic Singleton

Generics enables a whole new functionality. Combining this with the power of a singleton class creates something really interesting: a generic singleton class! So this way you can get a singleton instance of any type of class you want.

public class GenericSingleton<T> where T : class, new()

{

    private static T instance;

 

    public static T GetInstance()

    {

        lock (typeof(T))

        {

            if (instance == null)

            {

                instance = new T();

            }

            return instance;

        }

    }

}

Now I can create singleton instances of several classes with the same singleton class. I created a singleton instance of the LabCollectChannelFactory class and initiated the channels.

Deraeve.General.GenericSingleton<LabCollectChannelFactory>.GetInstance().InitChannels();

The LabColectChannelFactory will stay alive as long as the singleton lives. In the channel factory I implemented the IDisposable interface and I clear all channels when the Dispose method is called. This way I do not need to create an instance and initiate the channels each time a WCF call is made. This is only on the client side, the server side can also work with singleton class calls. You can use this singleton class for all your needs. The lock function ensure thread safety!

So now, after I initiated the channelfactory once, I can start calling the WCF functions:

List<User> AllActiveUsers = Deraeve.General.GenericSingleton <LabCollectChannelFactory>.GetInstance().UserManager.GetAllUsers();